summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/workqueue.txt103
-rw-r--r--arch/arm/Kconfig49
-rw-r--r--arch/arm/boot/compressed/.gitignore9
-rw-r--r--arch/arm/boot/compressed/Makefile32
-rw-r--r--arch/arm/boot/compressed/atags_to_fdt.c102
-rw-r--r--arch/arm/boot/compressed/head.S121
-rw-r--r--arch/arm/boot/compressed/libfdt_env.h15
-rw-r--r--arch/arm/boot/compressed/misc.c42
-rw-r--r--arch/arm/boot/compressed/string.c127
-rw-r--r--arch/arm/boot/compressed/vmlinux.lds.in4
-rw-r--r--arch/arm/boot/dts/tegra20-harmony.dts (renamed from arch/arm/boot/dts/tegra-harmony.dts)0
-rw-r--r--arch/arm/boot/dts/tegra20-seaboard.dts (renamed from arch/arm/boot/dts/tegra-seaboard.dts)0
-rw-r--r--arch/arm/boot/dts/tegra20-ventana.dts8
-rw-r--r--arch/arm/boot/dts/tegra20-whistler.dts8
-rw-r--r--arch/arm/boot/dts/tegra30-cardhu.dts8
-rw-r--r--arch/arm/boot/dts/tegra30-enterprise.dts8
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi5
-rw-r--r--arch/arm/configs/tegra3_android_defconfig31
-rw-r--r--arch/arm/configs/tegra3_defconfig12
-rw-r--r--arch/arm/configs/tegra_android_defconfig2
-rw-r--r--arch/arm/configs/tegra_e1853_gnu_linux_defconfig219
-rw-r--r--arch/arm/configs/tegra_p1852_android_defconfig339
-rw-r--r--arch/arm/configs/tegra_p1852_gnu_linux_defconfig4
-rw-r--r--arch/arm/configs/tegra_p1852_mods_defconfig206
-rw-r--r--arch/arm/include/asm/bug.h70
-rw-r--r--arch/arm/include/asm/hardware/cache-l2x0.h1
-rw-r--r--arch/arm/include/asm/mutex.h122
-rw-r--r--arch/arm/include/asm/outercache.h8
-rw-r--r--arch/arm/kernel/devtree.c14
-rw-r--r--arch/arm/kernel/smp.c3
-rw-r--r--arch/arm/kernel/traps.c33
-rw-r--r--arch/arm/kernel/vmlinux.lds.S21
-rw-r--r--arch/arm/mach-tegra/Kconfig68
-rw-r--r--arch/arm/mach-tegra/Makefile9
-rw-r--r--arch/arm/mach-tegra/Makefile.boot8
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.c383
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.h33
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power2.c23
-rw-r--r--arch/arm/mach-tegra/board-aruba-panel.c3
-rw-r--r--arch/arm/mach-tegra/board-aruba-sdhci.c3
-rw-r--r--arch/arm/mach-tegra/board-aruba-sensors.c2
-rw-r--r--arch/arm/mach-tegra/board-aruba.c9
-rw-r--r--arch/arm/mach-tegra/board-cardhu-irda.c178
-rw-r--r--arch/arm/mach-tegra/board-cardhu-kbc.c13
-rw-r--r--arch/arm/mach-tegra/board-cardhu-memory.c790
-rw-r--r--arch/arm/mach-tegra/board-cardhu-panel.c39
-rw-r--r--arch/arm/mach-tegra/board-cardhu-pinmux.c93
-rw-r--r--arch/arm/mach-tegra/board-cardhu-power.c41
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sdhci.c21
-rw-r--r--arch/arm/mach-tegra/board-cardhu-sensors.c45
-rw-r--r--arch/arm/mach-tegra/board-cardhu.c116
-rw-r--r--arch/arm/mach-tegra/board-cardhu.h4
-rw-r--r--arch/arm/mach-tegra/board-e1853-panel.c202
-rw-r--r--arch/arm/mach-tegra/board-e1853-pinmux.c502
-rw-r--r--arch/arm/mach-tegra/board-e1853-sdhci.c83
-rw-r--r--arch/arm/mach-tegra/board-e1853.c421
-rw-r--r--arch/arm/mach-tegra/board-e1853.h28
-rw-r--r--arch/arm/mach-tegra/board-enterprise-memory.c12
-rw-r--r--arch/arm/mach-tegra/board-enterprise-panel.c130
-rw-r--r--arch/arm/mach-tegra/board-enterprise-pinmux.c727
-rw-r--r--arch/arm/mach-tegra/board-enterprise-power.c318
-rw-r--r--arch/arm/mach-tegra/board-enterprise-sdhci.c65
-rw-r--r--arch/arm/mach-tegra/board-enterprise-sensors.c164
-rw-r--r--arch/arm/mach-tegra/board-enterprise.c277
-rw-r--r--arch/arm/mach-tegra/board-enterprise.h12
-rw-r--r--arch/arm/mach-tegra/board-harmony-panel.c7
-rw-r--r--arch/arm/mach-tegra/board-harmony.c30
-rw-r--r--arch/arm/mach-tegra/board-kai-memory.c22
-rw-r--r--arch/arm/mach-tegra/board-kai-power.c8
-rw-r--r--arch/arm/mach-tegra/board-kai-sdhci.c19
-rw-r--r--arch/arm/mach-tegra/board-kai-sensors.c40
-rw-r--r--arch/arm/mach-tegra/board-kai.c21
-rw-r--r--arch/arm/mach-tegra/board-p1852-panel.c412
-rw-r--r--arch/arm/mach-tegra/board-p1852-pinmux.c24
-rw-r--r--arch/arm/mach-tegra/board-p1852.c91
-rw-r--r--arch/arm/mach-tegra/board-p1852.h12
-rw-r--r--arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c4
-rw-r--r--arch/arm/mach-tegra/board-touch-raydium_spi.c2
-rw-r--r--arch/arm/mach-tegra/board-ventana-pinmux.c1
-rw-r--r--arch/arm/mach-tegra/board-ventana.c44
-rw-r--r--arch/arm/mach-tegra/board-ventana.h3
-rw-r--r--arch/arm/mach-tegra/board-whistler.c42
-rw-r--r--arch/arm/mach-tegra/board.h4
-rw-r--r--arch/arm/mach-tegra/clock.h3
-rw-r--r--arch/arm/mach-tegra/clocks_stats.c259
-rw-r--r--arch/arm/mach-tegra/common-t3.c15
-rw-r--r--arch/arm/mach-tegra/common.c190
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c26
-rw-r--r--arch/arm/mach-tegra/cpu-tegra3.c67
-rw-r--r--arch/arm/mach-tegra/cpuidle.c12
-rw-r--r--arch/arm/mach-tegra/cpuquiet.c32
-rw-r--r--arch/arm/mach-tegra/devices.c37
-rw-r--r--arch/arm/mach-tegra/devices.h1
-rw-r--r--arch/arm/mach-tegra/dvfs.c12
-rw-r--r--arch/arm/mach-tegra/dvfs.h17
-rw-r--r--arch/arm/mach-tegra/fuse.h1
-rw-r--r--arch/arm/mach-tegra/headsmp.S12
-rw-r--r--arch/arm/mach-tegra/i2c_error_recovery.c5
-rw-r--r--arch/arm/mach-tegra/include/mach/dc.h16
-rw-r--r--arch/arm/mach-tegra/include/mach/io_dpd.h30
-rw-r--r--arch/arm/mach-tegra/include/mach/latency_allowance.h40
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra-bb-power.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_asoc_pdata.h15
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_e1853_pdata.h55
-rw-r--r--arch/arm/mach-tegra/iovmm.c8
-rw-r--r--arch/arm/mach-tegra/irq.c6
-rw-r--r--arch/arm/mach-tegra/la_priv_common.h71
-rw-r--r--arch/arm/mach-tegra/latency_allowance.c399
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-gpio.c1
-rw-r--r--arch/arm/mach-tegra/p852/board-p852-sdhci.c6
-rw-r--r--arch/arm/mach-tegra/p852/board-p852.c5
-rw-r--r--arch/arm/mach-tegra/pcie.c237
-rw-r--r--arch/arm/mach-tegra/pinmux-t3-tables.c8
-rw-r--r--arch/arm/mach-tegra/platsmp.c22
-rw-r--r--arch/arm/mach-tegra/pm-irq.c7
-rw-r--r--arch/arm/mach-tegra/pm-t2.c18
-rw-r--r--arch/arm/mach-tegra/pm-t3.c136
-rw-r--r--arch/arm/mach-tegra/pm.c66
-rw-r--r--arch/arm/mach-tegra/pm.h32
-rw-r--r--arch/arm/mach-tegra/pwm.c50
-rw-r--r--arch/arm/mach-tegra/sleep-t3.S150
-rw-r--r--arch/arm/mach-tegra/sleep.S79
-rw-r--r--arch/arm/mach-tegra/sleep.h40
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c16
-rw-r--r--arch/arm/mach-tegra/tegra2_usb_phy.c219
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c85
-rw-r--r--arch/arm/mach-tegra/tegra3_dvfs.c265
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.c66
-rw-r--r--arch/arm/mach-tegra/tegra3_emc.h44
-rw-r--r--arch/arm/mach-tegra/tegra3_la_priv.h226
-rw-r--r--arch/arm/mach-tegra/tegra3_speedo.c22
-rw-r--r--arch/arm/mach-tegra/tegra3_thermal.c7
-rw-r--r--arch/arm/mach-tegra/tegra3_usb_phy.c346
-rw-r--r--arch/arm/mach-tegra/tegra_fuse.c (renamed from arch/arm/mach-tegra/fuse.c)46
-rw-r--r--arch/arm/mach-tegra/tegra_odm_fuses.c12
-rw-r--r--arch/arm/mach-tegra/tegra_usb_modem_power.c5
-rw-r--r--arch/arm/mach-tegra/tegra_usb_phy.h4
-rw-r--r--arch/arm/mach-tegra/timer-t3.c2
-rw-r--r--arch/arm/mach-tegra/timer.c91
-rw-r--r--arch/arm/mach-tegra/timer.h3
-rw-r--r--arch/arm/mach-tegra/usb_phy.c73
-rw-r--r--arch/arm/mach-tegra/wakeups-t2.h3
-rw-r--r--arch/arm/mach-tegra/wakeups-t3.c3
-rw-r--r--arch/arm/mm/cache-l2x0.c8
-rw-r--r--arch/arm/mm/init.c6
-rw-r--r--arch/arm/mm/mmu.c2
-rw-r--r--arch/arm/mm/pageattr.c72
-rw-r--r--arch/arm/tools/mach-types4
-rw-r--r--chromeos/config/armel/config.common.armel12
-rw-r--r--chromeos/config/armel/config.flavour.chromeos-tegra35
-rw-r--r--chromeos/config/armel/config.flavour.chromiumos-arm2
-rw-r--r--chromeos/config/config.common.chromeos9
-rw-r--r--chromeos/config/i386/config.common.i3861
-rw-r--r--chromeos/config/x86_64/config.common.x86_641
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/base/power/runtime.c4
-rw-r--r--drivers/char/agp/Makefile1
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c334
-rw-r--r--drivers/cpufreq/cpufreq_stats.c28
-rw-r--r--drivers/cpuquiet/governor.c14
-rw-r--r--drivers/crypto/Makefile2
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/gpio-tegra.c8
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/tegra-tsensor.c82
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-tegra.c212
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c10
-rw-r--r--drivers/iommu/Makefile2
-rw-r--r--drivers/iommu/tegra-smmu.c19
-rw-r--r--drivers/media/video/tegra/ad5816.c135
-rw-r--r--drivers/media/video/tegra/ar0832_main.c25
-rw-r--r--drivers/media/video/tegra/nvavp/nvavp_dev.c149
-rw-r--r--drivers/media/video/tegra/ov5650.c5
-rw-r--r--drivers/media/video/tegra/ov9726.c57
-rw-r--r--drivers/media/video/tegra/sh532u.c8
-rw-r--r--drivers/media/video/tegra/tegra_camera.c24
-rw-r--r--drivers/mfd/Kconfig42
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/max77665.c371
-rw-r--r--drivers/mfd/tlv320aic3262-core.c885
-rw-r--r--drivers/mfd/tlv320aic3262-irq.c204
-rw-r--r--drivers/mfd/tps65090.c385
-rw-r--r--drivers/mfd/tps80031.c417
-rw-r--r--drivers/misc/Kconfig7
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/bcm4329_rfkill.c2
-rw-r--r--drivers/misc/inv_mpu/mpu6050/mldl_cfg.c10
-rw-r--r--drivers/misc/tegra-baseband/bb-m7400.c2
-rw-r--r--drivers/misc/tegra-baseband/bb-power.c3
-rw-r--r--drivers/misc/tegra-cec/Makefile2
-rw-r--r--drivers/misc/tegra-throughput.c242
-rw-r--r--drivers/mmc/core/core.c26
-rw-r--r--drivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/sd_ops.c26
-rw-r--r--drivers/mmc/core/sd_ops.h3
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/sdhci-tegra.c123
-rw-r--r--drivers/mmc/host/sdhci.c38
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/tegra_nand.c1
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/tegra_nor.c87
-rw-r--r--drivers/net/caif/Makefile1
-rw-r--r--drivers/net/usb/cdc_ether.c8
-rw-r--r--drivers/net/usb/raw_ip_net.c185
-rw-r--r--drivers/net/usb/usbnet.c74
-rw-r--r--drivers/net/wireless/bcmdhd/Kconfig9
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile18
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c1
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c5
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c5
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h6
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c127
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c57
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdevs.h3
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h9
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndpmu.h5
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbchipc.h18
-rw-r--r--drivers/net/wireless/bcmdhd/include/siutils.h4
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h10
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c782
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h8
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c48
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h11
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c1
-rw-r--r--drivers/power/Makefile1
-rw-r--r--drivers/power/max17048_battery.c20
-rw-r--r--drivers/power/smb349-charger.c13
-rw-r--r--drivers/power/tps80031-charger.c110
-rw-r--r--drivers/power/tps80031_battery_gauge.c17
-rw-r--r--drivers/regulator/Kconfig22
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/core.c14
-rw-r--r--drivers/regulator/tps51632-regulator.c307
-rw-r--r--drivers/regulator/tps62360-regulator.c6
-rw-r--r--drivers/regulator/tps65090-regulator.c296
-rw-r--r--drivers/regulator/tps80031-regulator.c397
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/alarm.c1
-rw-r--r--drivers/rtc/rtc-max77663.c11
-rw-r--r--drivers/rtc/rtc-tps6591x.c28
-rw-r--r--drivers/rtc/rtc-tps80031.c12
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/spi-tegra.c117
-rw-r--r--drivers/spi/spi_slave_tegra.c2
-rw-r--r--drivers/staging/android/logger.c190
-rw-r--r--drivers/staging/android/logger.h29
-rw-r--r--drivers/staging/brcm80211/Kconfig1
-rw-r--r--drivers/staging/brcm80211/Makefile4
-rw-r--r--drivers/staging/brcm80211/README65
-rw-r--r--drivers/staging/brcm80211/TODO13
-rw-r--r--drivers/staging/brcm80211/brcmfmac/Makefile10
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh.c505
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c1228
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd.h526
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_bus.h39
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_cdc.c220
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_common.c887
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_dbg.h46
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_linux.c1152
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_proto.h25
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_sdio.c6651
-rw-r--r--drivers/staging/brcm80211/brcmfmac/sdio_host.h293
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c3396
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h91
-rw-r--r--drivers/staging/brcm80211/brcmsmac/Makefile21
-rw-r--r--drivers/staging/brcm80211/brcmsmac/aiutils.c1248
-rw-r--r--drivers/staging/brcm80211/brcmsmac/aiutils.h310
-rw-r--r--drivers/staging/brcm80211/brcmsmac/alloc.c275
-rw-r--r--drivers/staging/brcm80211/brcmsmac/ampdu.c594
-rw-r--r--drivers/staging/brcm80211/brcmsmac/antsel.c240
-rw-r--r--drivers/staging/brcm80211/brcmsmac/bmac.c3593
-rw-r--r--drivers/staging/brcm80211/brcmsmac/bmac.h174
-rw-r--r--drivers/staging/brcm80211/brcmsmac/brcms_trace_events.c (renamed from drivers/staging/brcm80211/brcmsmac/alloc.h)12
-rw-r--r--drivers/staging/brcm80211/brcmsmac/brcms_trace_events.h92
-rw-r--r--drivers/staging/brcm80211/brcmsmac/channel.c1216
-rw-r--r--drivers/staging/brcm80211/brcmsmac/channel.h87
-rw-r--r--drivers/staging/brcm80211/brcmsmac/d11.h705
-rw-r--r--drivers/staging/brcm80211/brcmsmac/dma.c1686
-rw-r--r--drivers/staging/brcm80211/brcmsmac/dma.h200
-rw-r--r--drivers/staging/brcm80211/brcmsmac/mac80211_if.c1557
-rw-r--r--drivers/staging/brcm80211/brcmsmac/mac80211_if.h38
-rw-r--r--drivers/staging/brcm80211/brcmsmac/main.c9417
-rw-r--r--drivers/staging/brcm80211/brcmsmac/main.h950
-rw-r--r--drivers/staging/brcm80211/brcmsmac/nicpci.c181
-rw-r--r--drivers/staging/brcm80211/brcmsmac/nicpci.h41
-rw-r--r--drivers/staging/brcm80211/brcmsmac/otp.c237
-rw-r--r--drivers/staging/brcm80211/brcmsmac/otp.h15
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c1163
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phy_hal.h85
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phy_int.h212
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phy_lcn.c3478
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phy_n.c15452
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phy_qmath.c172
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phytbl_lcn.c1236
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.c131
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.h24
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy_shim.c53
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy_shim.h82
-rw-r--r--drivers/staging/brcm80211/brcmsmac/pmu.c76
-rw-r--r--drivers/staging/brcm80211/brcmsmac/pmu.h14
-rw-r--r--drivers/staging/brcm80211/brcmsmac/pub.h785
-rw-r--r--drivers/staging/brcm80211/brcmsmac/rate.c182
-rw-r--r--drivers/staging/brcm80211/brcmsmac/rate.h299
-rw-r--r--drivers/staging/brcm80211/brcmsmac/scb.h61
-rw-r--r--drivers/staging/brcm80211/brcmsmac/srom.c1427
-rw-r--r--drivers/staging/brcm80211/brcmsmac/srom.h4
-rw-r--r--drivers/staging/brcm80211/brcmsmac/stf.c259
-rw-r--r--drivers/staging/brcm80211/brcmsmac/stf.h6
-rw-r--r--drivers/staging/brcm80211/brcmsmac/types.h331
-rw-r--r--drivers/staging/brcm80211/brcmsmac/ucode_loader.c120
-rw-r--r--drivers/staging/brcm80211/brcmsmac/ucode_loader.h50
-rw-r--r--drivers/staging/brcm80211/brcmutil/Makefile3
-rw-r--r--drivers/staging/brcm80211/brcmutil/utils.c415
-rw-r--r--drivers/staging/brcm80211/brcmutil/wifi.c131
-rw-r--r--drivers/staging/brcm80211/include/brcmu_utils.h270
-rw-r--r--drivers/staging/brcm80211/include/brcmu_wifi.h190
-rw-r--r--drivers/staging/brcm80211/include/chipcommon.h13
-rw-r--r--drivers/staging/brcm80211/include/defs.h32
-rw-r--r--drivers/staging/brcm80211/include/soc.h9
-rw-r--r--drivers/staging/nvec/nvec.c1
-rw-r--r--drivers/tty/serial/Makefile1
-rw-r--r--drivers/tty/serial/tegra_hsuart.c101
-rw-r--r--drivers/usb/class/cdc-acm.c2
-rw-r--r--drivers/usb/gadget/Kconfig2
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/android.c68
-rw-r--r--drivers/usb/gadget/f_accessory.c404
-rw-r--r--drivers/usb/gadget/f_audio_source.c827
-rw-r--r--drivers/usb/gadget/tegra_udc.c178
-rw-r--r--drivers/usb/gadget/tegra_udc.h21
-rw-r--r--drivers/usb/host/ehci-q.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c18
-rw-r--r--drivers/usb/host/ehci.h22
-rw-r--r--drivers/usb/otg/Makefile1
-rw-r--r--drivers/usb/otg/tegra-otg.c60
-rw-r--r--drivers/usb/serial/baseband_usb_chr.c98
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/tegra/Kconfig19
-rw-r--r--drivers/video/tegra/dc/csc.c2
-rw-r--r--drivers/video/tegra/dc/dc.c204
-rw-r--r--drivers/video/tegra/dc/dc_priv.h19
-rw-r--r--drivers/video/tegra/dc/dc_sysfs.c14
-rw-r--r--drivers/video/tegra/dc/dsi.c549
-rw-r--r--drivers/video/tegra/dc/ext/dev.c110
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h4
-rw-r--r--drivers/video/tegra/dc/hdmi.c65
-rw-r--r--drivers/video/tegra/dc/mode.c25
-rw-r--r--drivers/video/tegra/dc/nvsd.c5
-rw-r--r--drivers/video/tegra/dc/window.c24
-rw-r--r--drivers/video/tegra/fb.c66
-rw-r--r--drivers/video/tegra/host/bus.c2
-rw-r--r--drivers/video/tegra/host/bus_client.c3
-rw-r--r--drivers/video/tegra/host/chip_support.h1
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.c4
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.h3
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.c14
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c28
-rw-r--r--drivers/video/tegra/host/gr3d/scale3d.c602
-rw-r--r--drivers/video/tegra/host/host1x/host1x.c15
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c11
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.c8
-rw-r--r--drivers/video/tegra/host/host1x/host1x_intr.c13
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c18
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c23
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c12
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h2
-rw-r--r--drivers/video/tegra/host/nvhost_job.c31
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c6
-rw-r--r--drivers/video/tegra/host/t30/t30.c2
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c18
-rw-r--r--drivers/video/tegra/nvmap/nvmap_common.h3
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c7
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c99
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.c5
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c58
-rw-r--r--drivers/w1/masters/Makefile1
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/tegra_wdt.c5
-rw-r--r--include/linux/cpu.h5
-rw-r--r--include/linux/cpuquiet.h4
-rw-r--r--include/linux/mfd/max77665.h92
-rw-r--r--include/linux/mfd/tlv320aic3262-core.h237
-rw-r--r--include/linux/mfd/tlv320aic3262-registers.h323
-rw-r--r--include/linux/mfd/tps65090.h60
-rw-r--r--include/linux/mfd/tps80031.h16
-rw-r--r--include/linux/mmc/card.h12
-rw-r--r--include/linux/mmc/host.h10
-rw-r--r--include/linux/mmc/sd.h13
-rw-r--r--include/linux/nvhost.h6
-rw-r--r--include/linux/nvmap.h3
-rw-r--r--include/linux/platform_data/tegra_nor.h46
-rw-r--r--include/linux/platform_data/tegra_usb.h12
-rw-r--r--include/linux/regulator/driver.h2
-rw-r--r--include/linux/regulator/tps51632-regulator.h54
-rw-r--r--include/linux/regulator/tps65090-regulator.h67
-rw-r--r--include/linux/regulator/tps80031-regulator.h43
-rw-r--r--include/linux/tegra_nvavp.h8
-rw-r--r--include/linux/tegra_uart.h8
-rw-r--r--include/linux/throughput_ioctl.h39
-rw-r--r--include/linux/usb/f_accessory.h65
-rw-r--r--include/linux/usb/usbnet.h3
-rw-r--r--include/media/nvc_focus.h8
-rw-r--r--include/media/ov9726.h12
-rw-r--r--include/media/tegra_camera.h10
-rw-r--r--include/sound/soc-dapm.h5
-rw-r--r--include/sound/soc.h1
-rw-r--r--include/trace/events/nvevent.h100
-rw-r--r--include/trace/events/power.h14
-rw-r--r--include/trace/events/workqueue.h2
-rw-r--r--kernel/kthread.c11
-rw-r--r--kernel/pm_qos_params.c61
-rw-r--r--kernel/workqueue.c1139
-rw-r--r--mm/failslab.c19
-rw-r--r--scripts/Kbuild.include2
-rwxr-xr-xscripts/setlocalversion23
-rw-r--r--security/tf_driver/s_version.h2
-rw-r--r--security/tf_driver/tf_protocol.h2
-rw-r--r--sound/pci/hda/hda_codec.c25
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_eld.c4
-rw-r--r--sound/soc/codecs/Kconfig1
-rw-r--r--sound/soc/codecs/Makefile3
-rw-r--r--sound/soc/codecs/aic3262_codec_ops.c424
-rw-r--r--sound/soc/codecs/aic3262_codec_ops.h44
-rw-r--r--sound/soc/codecs/aic326x_tiload.c231
-rw-r--r--sound/soc/codecs/aic326x_tiload.h5
-rw-r--r--sound/soc/codecs/aic3xxx_cfw.h427
-rw-r--r--sound/soc/codecs/aic3xxx_cfw_ops.c922
-rw-r--r--sound/soc/codecs/aic3xxx_cfw_ops.h76
-rw-r--r--sound/soc/codecs/max98088.c2
-rw-r--r--sound/soc/codecs/tlv320aic3262_default_fw.h582
-rw-r--r--sound/soc/codecs/tlv320aic326x.c5581
-rw-r--r--sound/soc/codecs/tlv320aic326x.h645
-rw-r--r--sound/soc/soc-core.c1
-rw-r--r--sound/soc/soc-dapm.c60
-rw-r--r--sound/soc/tegra/Makefile5
-rw-r--r--sound/soc/tegra/tegra30_i2s.c7
-rw-r--r--sound/soc/tegra/tegra_aic326x.c226
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c97
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h12
-rw-r--r--sound/soc/tegra/tegra_max98088.c193
-rw-r--r--sound/soc/tegra/tegra_max98095.c57
-rw-r--r--sound/soc/tegra/tegra_pcm.c5
-rw-r--r--sound/soc/tegra/tegra_pcm.h1
-rw-r--r--sound/soc/tegra/tegra_rt5640.c103
-rw-r--r--sound/soc/tegra/tegra_vcm.c (renamed from sound/soc/tegra/tegra_p1852.c)97
-rw-r--r--sound/soc/tegra/tegra_wm8753.c88
-rw-r--r--sound/soc/tegra/tegra_wm8903.c132
-rw-r--r--sound/usb/card.c51
453 files changed, 52614 insertions, 46954 deletions
diff --git a/Documentation/workqueue.txt b/Documentation/workqueue.txt
index a0b577de918f..a6ab4b62d926 100644
--- a/Documentation/workqueue.txt
+++ b/Documentation/workqueue.txt
@@ -89,25 +89,28 @@ called thread-pools.
The cmwq design differentiates between the user-facing workqueues that
subsystems and drivers queue work items on and the backend mechanism
-which manages thread-pool and processes the queued work items.
+which manages thread-pools and processes the queued work items.
The backend is called gcwq. There is one gcwq for each possible CPU
-and one gcwq to serve work items queued on unbound workqueues.
+and one gcwq to serve work items queued on unbound workqueues. Each
+gcwq has two thread-pools - one for normal work items and the other
+for high priority ones.
Subsystems and drivers can create and queue work items through special
workqueue API functions as they see fit. They can influence some
aspects of the way the work items are executed by setting flags on the
workqueue they are putting the work item on. These flags include
-things like CPU locality, reentrancy, concurrency limits and more. To
-get a detailed overview refer to the API description of
+things like CPU locality, reentrancy, concurrency limits, priority and
+more. To get a detailed overview refer to the API description of
alloc_workqueue() below.
-When a work item is queued to a workqueue, the target gcwq is
-determined according to the queue parameters and workqueue attributes
-and appended on the shared worklist of the gcwq. For example, unless
-specifically overridden, a work item of a bound workqueue will be
-queued on the worklist of exactly that gcwq that is associated to the
-CPU the issuer is running on.
+When a work item is queued to a workqueue, the target gcwq and
+thread-pool is determined according to the queue parameters and
+workqueue attributes and appended on the shared worklist of the
+thread-pool. For example, unless specifically overridden, a work item
+of a bound workqueue will be queued on the worklist of either normal
+or highpri thread-pool of the gcwq that is associated to the CPU the
+issuer is running on.
For any worker pool implementation, managing the concurrency level
(how many execution contexts are active) is an important issue. cmwq
@@ -115,26 +118,26 @@ tries to keep the concurrency at a minimal but sufficient level.
Minimal to save resources and sufficient in that the system is used at
its full capacity.
-Each gcwq bound to an actual CPU implements concurrency management by
-hooking into the scheduler. The gcwq is notified whenever an active
-worker wakes up or sleeps and keeps track of the number of the
-currently runnable workers. Generally, work items are not expected to
-hog a CPU and consume many cycles. That means maintaining just enough
-concurrency to prevent work processing from stalling should be
-optimal. As long as there are one or more runnable workers on the
-CPU, the gcwq doesn't start execution of a new work, but, when the
-last running worker goes to sleep, it immediately schedules a new
-worker so that the CPU doesn't sit idle while there are pending work
-items. This allows using a minimal number of workers without losing
-execution bandwidth.
+Each thread-pool bound to an actual CPU implements concurrency
+management by hooking into the scheduler. The thread-pool is notified
+whenever an active worker wakes up or sleeps and keeps track of the
+number of the currently runnable workers. Generally, work items are
+not expected to hog a CPU and consume many cycles. That means
+maintaining just enough concurrency to prevent work processing from
+stalling should be optimal. As long as there are one or more runnable
+workers on the CPU, the thread-pool doesn't start execution of a new
+work, but, when the last running worker goes to sleep, it immediately
+schedules a new worker so that the CPU doesn't sit idle while there
+are pending work items. This allows using a minimal number of workers
+without losing execution bandwidth.
Keeping idle workers around doesn't cost other than the memory space
for kthreads, so cmwq holds onto idle ones for a while before killing
them.
For an unbound wq, the above concurrency management doesn't apply and
-the gcwq for the pseudo unbound CPU tries to start executing all work
-items as soon as possible. The responsibility of regulating
+the thread-pools for the pseudo unbound CPU try to start executing all
+work items as soon as possible. The responsibility of regulating
concurrency level is on the users. There is also a flag to mark a
bound wq to ignore the concurrency management. Please refer to the
API section for details.
@@ -205,31 +208,22 @@ resources, scheduled and executed.
WQ_HIGHPRI
- Work items of a highpri wq are queued at the head of the
- worklist of the target gcwq and start execution regardless of
- the current concurrency level. In other words, highpri work
- items will always start execution as soon as execution
- resource is available.
+ Work items of a highpri wq are queued to the highpri
+ thread-pool of the target gcwq. Highpri thread-pools are
+ served by worker threads with elevated nice level.
- Ordering among highpri work items is preserved - a highpri
- work item queued after another highpri work item will start
- execution after the earlier highpri work item starts.
-
- Although highpri work items are not held back by other
- runnable work items, they still contribute to the concurrency
- level. Highpri work items in runnable state will prevent
- non-highpri work items from starting execution.
-
- This flag is meaningless for unbound wq.
+ Note that normal and highpri thread-pools don't interact with
+ each other. Each maintain its separate pool of workers and
+ implements concurrency management among its workers.
WQ_CPU_INTENSIVE
Work items of a CPU intensive wq do not contribute to the
concurrency level. In other words, runnable CPU intensive
- work items will not prevent other work items from starting
- execution. This is useful for bound work items which are
- expected to hog CPU cycles so that their execution is
- regulated by the system scheduler.
+ work items will not prevent other work items in the same
+ thread-pool from starting execution. This is useful for bound
+ work items which are expected to hog CPU cycles so that their
+ execution is regulated by the system scheduler.
Although CPU intensive work items don't contribute to the
concurrency level, start of their executions is still
@@ -239,14 +233,6 @@ resources, scheduled and executed.
This flag is meaningless for unbound wq.
- WQ_HIGHPRI | WQ_CPU_INTENSIVE
-
- This combination makes the wq avoid interaction with
- concurrency management completely and behave as a simple
- per-CPU execution context provider. Work items queued on a
- highpri CPU-intensive wq start execution as soon as resources
- are available and don't affect execution of other work items.
-
@max_active:
@max_active determines the maximum number of execution contexts per
@@ -328,20 +314,7 @@ If @max_active == 2,
35 w2 wakes up and finishes
Now, let's assume w1 and w2 are queued to a different wq q1 which has
-WQ_HIGHPRI set,
-
- TIME IN MSECS EVENT
- 0 w1 and w2 start and burn CPU
- 5 w1 sleeps
- 10 w2 sleeps
- 10 w0 starts and burns CPU
- 15 w0 sleeps
- 15 w1 wakes up and finishes
- 20 w2 wakes up and finishes
- 25 w0 wakes up and burns CPU
- 30 w0 finishes
-
-If q1 has WQ_CPU_INTENSIVE set,
+WQ_CPU_INTENSIVE set,
TIME IN MSECS EVENT
0 w0 starts and burns CPU
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 16b259ab7aac..bc3e8dc005bb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1,3 +1,16 @@
+# 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/>.
config ARM
bool
default y
@@ -218,6 +231,10 @@ config ARM_PATCH_PHYS_VIRT_16BIT
to allow physical memory down to a theoretical minimum of 64K
boundaries.
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -1923,6 +1940,38 @@ config ZBOOT_ROM_SH_MOBILE_SDHI
endchoice
+config ARM_APPENDED_DTB
+ bool "Use appended device tree blob to zImage (EXPERIMENTAL)"
+ depends on OF && !ZBOOT_ROM && EXPERIMENTAL
+ help
+ With this option, the boot code will look for a device tree binary
+ (DTB) appended to zImage
+ (e.g. cat zImage <filename>.dtb > zImage_w_dtb).
+
+ This is meant as a backward compatibility convenience for those
+ systems with a bootloader that can't be upgraded to accommodate
+ the documented boot protocol using a device tree.
+
+ Beware that there is very little in terms of protection against
+ this option being confused by leftover garbage in memory that might
+ look like a DTB header after a reboot if no actual DTB is appended
+ to zImage. Do not leave this option active in a production kernel
+ if you don't intend to always append a DTB. Proper passing of the
+ location into r2 of a bootloader provided DTB is always preferable
+ to this option.
+
+config ARM_ATAG_DTB_COMPAT
+ bool "Supplement the appended DTB with traditional ATAG information"
+ depends on ARM_APPENDED_DTB
+ help
+ Some old bootloaders can't be updated to a DTB capable one, yet
+ they provide ATAGs with memory configuration, the ramdisk address,
+ the kernel cmdline string, etc. Such information is dynamically
+ provided by the bootloader and can't always be stored in a static
+ DTB. To allow a device tree enabled kernel to be used with such
+ bootloaders, this option allows zImage to extract the information
+ from the ATAG list and store it at run time into the appended DTB.
+
config CMDLINE
string "Default kernel command string"
default ""
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index c6028967d336..e0936a148516 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -5,3 +5,12 @@ piggy.lzo
piggy.lzma
vmlinux
vmlinux.lds
+
+# borrowed libfdt files
+fdt.c
+fdt.h
+fdt_ro.c
+fdt_rw.c
+fdt_wip.c
+libfdt.h
+libfdt_internal.h
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 0c74a6fab952..e4f32a8e002a 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -26,6 +26,10 @@ HEAD = head.o
OBJS += misc.o decompress.o
FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c
+# string library code (-Os is enforced to keep it much smaller)
+OBJS += string.o
+CFLAGS_string.o := -Os
+
#
# Architecture dependencies
#
@@ -89,21 +93,41 @@ suffix_$(CONFIG_KERNEL_GZIP) = gzip
suffix_$(CONFIG_KERNEL_LZO) = lzo
suffix_$(CONFIG_KERNEL_LZMA) = lzma
+# Borrowed libfdt files for the ATAG compatibility mode
+
+libfdt := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c
+libfdt_hdrs := fdt.h libfdt.h libfdt_internal.h
+
+libfdt_objs := $(addsuffix .o, $(basename $(libfdt)))
+
+$(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
+ $(call cmd,shipped)
+
+$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
+ $(addprefix $(obj)/,$(libfdt_hdrs))
+
+ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
+OBJS += $(libfdt_objs) atags_to_fdt.o
+endif
+
targets := vmlinux vmlinux.lds \
piggy.$(suffix_y) piggy.$(suffix_y).o \
- font.o font.c head.o misc.o $(OBJS)
+ lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS)
# Make sure files are removed during clean
-extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S
+extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs)
ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
endif
-ccflags-y := -fpic -fno-builtin
+ccflags-y := -fpic -fno-builtin -I$(obj)
asflags-y := -Wa,-march=all
+# Supply kernel BSS size to the decompressor via a linker symbol.
+KBSS_SZ = $(shell size $(obj)/../../../../vmlinux | awk 'END{print $$3}')
+LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
@@ -123,7 +147,7 @@ LDFLAGS_vmlinux += -T
# For __aeabi_uidivmod
lib1funcs = $(obj)/lib1funcs.o
-$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
+$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
$(call cmd,shipped)
# We need to prevent any GOTOFF relocs being used with references
diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c
new file mode 100644
index 000000000000..05c548875e3d
--- /dev/null
+++ b/arch/arm/boot/compressed/atags_to_fdt.c
@@ -0,0 +1,102 @@
+#include <asm/setup.h>
+#include <libfdt.h>
+
+static int node_offset(void *fdt, const char *node_path)
+{
+ int offset = fdt_path_offset(fdt, node_path);
+ if (offset == -FDT_ERR_NOTFOUND)
+ offset = fdt_add_subnode(fdt, 0, node_path);
+ return offset;
+}
+
+static int setprop(void *fdt, const char *node_path, const char *property,
+ uint32_t *val_array, int size)
+{
+ int offset = node_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+ return fdt_setprop(fdt, offset, property, val_array, size);
+}
+
+static int setprop_string(void *fdt, const char *node_path,
+ const char *property, const char *string)
+{
+ int offset = node_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+ return fdt_setprop_string(fdt, offset, property, string);
+}
+
+static int setprop_cell(void *fdt, const char *node_path,
+ const char *property, uint32_t val)
+{
+ int offset = node_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+ return fdt_setprop_cell(fdt, offset, property, val);
+}
+
+/*
+ * Convert and fold provided ATAGs into the provided FDT.
+ *
+ * REturn values:
+ * = 0 -> pretend success
+ * = 1 -> bad ATAG (may retry with another possible ATAG pointer)
+ * < 0 -> error from libfdt
+ */
+int atags_to_fdt(void *atag_list, void *fdt, int total_space)
+{
+ struct tag *atag = atag_list;
+ uint32_t mem_reg_property[2 * NR_BANKS];
+ int memcount = 0;
+ int ret;
+
+ /* make sure we've got an aligned pointer */
+ if ((u32)atag_list & 0x3)
+ return 1;
+
+ /* if we get a DTB here we're done already */
+ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
+ return 0;
+
+ /* validate the ATAG */
+ if (atag->hdr.tag != ATAG_CORE ||
+ (atag->hdr.size != tag_size(tag_core) &&
+ atag->hdr.size != 2))
+ return 1;
+
+ /* let's give it all the room it could need */
+ ret = fdt_open_into(fdt, fdt, total_space);
+ if (ret < 0)
+ return ret;
+
+ for_each_tag(atag, atag_list) {
+ if (atag->hdr.tag == ATAG_CMDLINE) {
+ setprop_string(fdt, "/chosen", "bootargs",
+ atag->u.cmdline.cmdline);
+ } else if (atag->hdr.tag == ATAG_MEM) {
+ if (memcount >= sizeof(mem_reg_property)/4)
+ continue;
+ mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
+ mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
+ } else if (atag->hdr.tag == ATAG_INITRD2) {
+ uint32_t initrd_start, initrd_size;
+ initrd_start = atag->u.initrd.start;
+ initrd_size = atag->u.initrd.size;
+ setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_start);
+ setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ initrd_start + initrd_size);
+ } else if (atag->hdr.tag == ATAG_SERIAL) {
+ uint32_t serial[2];
+ serial[0] = cpu_to_fdt32(atag->u.serialnr.high);
+ serial[1] = cpu_to_fdt32(atag->u.serialnr.low);
+ setprop(fdt, "/", "serial-num", serial, 8);
+ }
+ }
+
+ if (memcount)
+ setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
+
+ return fdt_pack(fdt);
+}
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 24701d6f72bc..e45767851a4c 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -216,6 +216,103 @@ restart: adr r0, LC0
mov r10, r6
#endif
+ mov r5, #0 @ init dtb size to 0
+#ifdef CONFIG_ARM_APPENDED_DTB
+/*
+ * r0 = delta
+ * r2 = BSS start
+ * r3 = BSS end
+ * r4 = final kernel address
+ * r5 = appended dtb size (still unknown)
+ * r6 = _edata
+ * r7 = architecture ID
+ * r8 = atags/device tree pointer
+ * r9 = size of decompressed image
+ * r10 = end of this image, including bss/stack/malloc space if non XIP
+ * r11 = GOT start
+ * r12 = GOT end
+ * sp = stack pointer
+ *
+ * if there are device trees (dtb) appended to zImage, advance r10 so that the
+ * dtb data will get relocated along with the kernel if necessary.
+ */
+
+ ldr lr, [r6, #0]
+#ifndef __ARMEB__
+ ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian
+#else
+ ldr r1, =0xd00dfeed
+#endif
+ cmp lr, r1
+ bne dtb_check_done @ not found
+
+#ifdef CONFIG_ARM_ATAG_DTB_COMPAT
+ /*
+ * OK... Let's do some funky business here.
+ * If we do have a DTB appended to zImage, and we do have
+ * an ATAG list around, we want the later to be translated
+ * and folded into the former here. To be on the safe side,
+ * let's temporarily move the stack away into the malloc
+ * area. No GOT fixup has occurred yet, but none of the
+ * code we're about to call uses any global variable.
+ */
+ add sp, sp, #0x10000
+ stmfd sp!, {r0-r3, ip, lr}
+ mov r0, r8
+ mov r1, r6
+ sub r2, sp, r6
+ bl atags_to_fdt
+
+ /*
+ * If returned value is 1, there is no ATAG at the location
+ * pointed by r8. Try the typical 0x100 offset from start
+ * of RAM and hope for the best.
+ */
+ cmp r0, #1
+ sub r0, r4, #(TEXT_OFFSET - 0x100)
+ mov r1, r6
+ sub r2, sp, r6
+ blne atags_to_fdt
+
+ ldmfd sp!, {r0-r3, ip, lr}
+ sub sp, sp, #0x10000
+#endif
+
+ mov r8, r6 @ use the appended device tree
+
+ /*
+ * Make sure that the DTB doesn't end up in the final
+ * kernel's .bss area. To do so, we adjust the decompressed
+ * kernel size to compensate if that .bss size is larger
+ * than the relocated code.
+ */
+ ldr r5, =_kernel_bss_size
+ adr r1, wont_overwrite
+ sub r1, r6, r1
+ subs r1, r5, r1
+ addhi r9, r9, r1
+
+ /* Get the dtb's size */
+ ldr r5, [r6, #4]
+#ifndef __ARMEB__
+ /* convert r5 (dtb size) to little endian */
+ eor r1, r5, r5, ror #16
+ bic r1, r1, #0x00ff0000
+ mov r5, r5, ror #8
+ eor r5, r5, r1, lsr #8
+#endif
+
+ /* preserve 64-bit alignment */
+ add r5, r5, #7
+ bic r5, r5, #7
+
+ /* relocate some pointers past the appended dtb */
+ add r6, r6, r5
+ add r10, r10, r5
+ add sp, sp, r5
+dtb_check_done:
+#endif
+
/*
* Check to see if we will overwrite ourselves.
* r4 = final kernel address
@@ -223,15 +320,14 @@ restart: adr r0, LC0
* r10 = end of this image, including bss/stack/malloc space if non XIP
* We basically want:
* r4 - 16k page directory >= r10 -> OK
- * r4 + image length <= current position (pc) -> OK
+ * r4 + image length <= address of wont_overwrite -> OK
*/
add r10, r10, #16384
cmp r4, r10
bhs wont_overwrite
add r10, r4, r9
- ARM( cmp r10, pc )
- THUMB( mov lr, pc )
- THUMB( cmp r10, lr )
+ adr r9, wont_overwrite
+ cmp r10, r9
bls wont_overwrite
/*
@@ -285,14 +381,16 @@ wont_overwrite:
* r2 = BSS start
* r3 = BSS end
* r4 = kernel execution address
+ * r5 = appended dtb size (0 if not present)
* r7 = architecture ID
* r8 = atags pointer
* r11 = GOT start
* r12 = GOT end
* sp = stack pointer
*/
- teq r0, #0
+ orrs r1, r0, r5
beq not_relocated
+
add r11, r11, r0
add r12, r12, r0
@@ -307,12 +405,21 @@ wont_overwrite:
/*
* Relocate all entries in the GOT table.
+ * Bump bss entries to _edata + dtb size
*/
1: ldr r1, [r11, #0] @ relocate entries in the GOT
- add r1, r1, r0 @ table. This fixes up the
- str r1, [r11], #4 @ C references.
+ add r1, r1, r0 @ This fixes up C references
+ cmp r1, r2 @ if entry >= bss_start &&
+ cmphs r3, r1 @ bss_end > entry
+ addhi r1, r1, r5 @ entry += dtb size
+ str r1, [r11], #4 @ next entry
cmp r11, r12
blo 1b
+
+ /* bump our bss pointers too */
+ add r2, r2, r5
+ add r3, r3, r5
+
#else
/*
diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h
new file mode 100644
index 000000000000..1f4e71876b00
--- /dev/null
+++ b/arch/arm/boot/compressed/libfdt_env.h
@@ -0,0 +1,15 @@
+#ifndef _ARM_LIBFDT_ENV_H
+#define _ARM_LIBFDT_ENV_H
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+#define fdt16_to_cpu(x) be16_to_cpu(x)
+#define cpu_to_fdt16(x) cpu_to_be16(x)
+#define fdt32_to_cpu(x) be32_to_cpu(x)
+#define cpu_to_fdt32(x) cpu_to_be32(x)
+#define fdt64_to_cpu(x) be64_to_cpu(x)
+#define cpu_to_fdt64(x) cpu_to_be64(x)
+
+#endif
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 832d37236c59..8e2a8fca5ed2 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -18,14 +18,9 @@
unsigned int __machine_arch_type;
-#define _LINUX_STRING_H_
-
#include <linux/compiler.h> /* for inline */
-#include <linux/types.h> /* for size_t */
-#include <linux/stddef.h> /* for NULL */
+#include <linux/types.h>
#include <linux/linkage.h>
-#include <asm/string.h>
-
static void putstr(const char *ptr);
extern void error(char *x);
@@ -101,41 +96,6 @@ static void putstr(const char *ptr)
flush();
}
-
-void *memcpy(void *__dest, __const void *__src, size_t __n)
-{
- int i = 0;
- unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
-
- for (i = __n >> 3; i > 0; i--) {
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- }
-
- if (__n & 1 << 2) {
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- }
-
- if (__n & 1 << 1) {
- *d++ = *s++;
- *d++ = *s++;
- }
-
- if (__n & 1)
- *d++ = *s++;
-
- return __dest;
-}
-
/*
* gzip declarations
*/
diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c
new file mode 100644
index 000000000000..36e53ef9200f
--- /dev/null
+++ b/arch/arm/boot/compressed/string.c
@@ -0,0 +1,127 @@
+/*
+ * arch/arm/boot/compressed/string.c
+ *
+ * Small subset of simple string routines
+ */
+
+#include <linux/string.h>
+
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+ int i = 0;
+ unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
+
+ for (i = __n >> 3; i > 0; i--) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1 << 2) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1 << 1) {
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1)
+ *d++ = *s++;
+
+ return __dest;
+}
+
+void *memmove(void *__dest, __const void *__src, size_t count)
+{
+ unsigned char *d = __dest;
+ const unsigned char *s = __src;
+
+ if (__dest == __src)
+ return __dest;
+
+ if (__dest < __src)
+ return memcpy(__dest, __src, count);
+
+ while (count--)
+ d[count] = s[count];
+ return __dest;
+}
+
+size_t strlen(const char *s)
+{
+ const char *sc = s;
+
+ while (*sc != '\0')
+ sc++;
+ return sc - s;
+}
+
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+ const unsigned char *su1 = cs, *su2 = ct, *end = su1 + count;
+ int res = 0;
+
+ while (su1 < end) {
+ res = *su1++ - *su2++;
+ if (res)
+ break;
+ }
+ return res;
+}
+
+int strcmp(const char *cs, const char *ct)
+{
+ unsigned char c1, c2;
+ int res = 0;
+
+ do {
+ c1 = *cs++;
+ c2 = *ct++;
+ res = c1 - c2;
+ if (res)
+ break;
+ } while (c1);
+ return res;
+}
+
+void *memchr(const void *s, int c, size_t count)
+{
+ const unsigned char *p = s;
+
+ while (count--)
+ if ((unsigned char)c == *p++)
+ return (void *)(p - 1);
+ return NULL;
+}
+
+char *strchr(const char *s, int c)
+{
+ while (*s != (char)c)
+ if (*s++ == '\0')
+ return NULL;
+ return (char *)s;
+}
+
+#undef memset
+
+void *memset(void *s, int c, size_t count)
+{
+ char *xs = s;
+ while (count--)
+ *xs++ = c;
+ return s;
+}
+
+void __memzero(void *s, size_t count)
+{
+ memset(s, 0, count);
+}
diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in
index 4e728834a1b9..4919f2ac8b89 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.in
+++ b/arch/arm/boot/compressed/vmlinux.lds.in
@@ -51,6 +51,10 @@ SECTIONS
_got_start = .;
.got : { *(.got) }
_got_end = .;
+
+ /* ensure the zImage file size is always a multiple of 64 bits */
+ /* (without a dummy byte, ld just ignores the empty section) */
+ .pad : { BYTE(0); . = ALIGN(8); }
_edata = .;
. = BSS_START;
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
index e5818668d091..e5818668d091 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index 64cedca6fc79..64cedca6fc79 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
new file mode 100644
index 000000000000..39f199755d5c
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+ model = "NVIDIA Tegra2 Ventana evaluation board";
+ compatible = "nvidia,ventana", "nvidia,tegra20";
+};
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
new file mode 100644
index 000000000000..e3a5939a42aa
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/include/ "tegra20.dtsi"
+
+/ {
+ model = "NVIDIA Tegra20 Whistler evaluation board";
+ compatible = "nvidia,whistler", "nvidia,tegra20";
+};
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dts b/arch/arm/boot/dts/tegra30-cardhu.dts
new file mode 100644
index 000000000000..35dce0bfb191
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-cardhu.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/include/ "tegra30.dtsi"
+
+/ {
+ model = "NVIDIA Tegra30 Cardhu evaluation board";
+ compatible = "nvidia,cardhu", "nvidia,tegra30";
+};
diff --git a/arch/arm/boot/dts/tegra30-enterprise.dts b/arch/arm/boot/dts/tegra30-enterprise.dts
new file mode 100644
index 000000000000..c78821ca9b15
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30-enterprise.dts
@@ -0,0 +1,8 @@
+/dts-v1/;
+
+/include/ "tegra30.dtsi"
+
+/ {
+ model = "NVIDIA Tegra30 Enterprise evaluation board";
+ compatible = "nvidia,enterprise", "nvidia,tegra30";
+};
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
new file mode 100644
index 000000000000..f568d44601a4
--- /dev/null
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -0,0 +1,5 @@
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "nvidia,tegra30";
+};
diff --git a/arch/arm/configs/tegra3_android_defconfig b/arch/arm/configs/tegra3_android_defconfig
index 0ab4493d3205..c738192e967d 100644
--- a/arch/arm/configs/tegra3_android_defconfig
+++ b/arch/arm/configs/tegra3_android_defconfig
@@ -26,26 +26,28 @@ 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_TAI=y
CONFIG_MACH_KAI=y
CONFIG_TEGRA_PWM=y
CONFIG_TEGRA_EMC_SCALING_ENABLE=y
CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND=y
CONFIG_USB_HOTPLUG=y
+CONFIG_TEGRA_GADGET_BOOST_CPU_FREQ=800
CONFIG_TEGRA_DYNAMIC_PWRDET=y
CONFIG_TEGRA_USB_MODEM_POWER=y
CONFIG_TEGRA_BB_XMM_POWER=y
CONFIG_TEGRA_BB_XMM_POWER2=m
CONFIG_TEGRA_PLLM_RESTRICTED=y
+CONFIG_TEGRA_LP1_950=y
CONFIG_ARM_ERRATA_742230=y
CONFIG_ARM_ERRATA_743622=y
CONFIG_ARM_ERRATA_751472=y
CONFIG_ARM_ERRATA_752520=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -54,6 +56,7 @@ CONFIG_AEABI=y
# CONFIG_OABI_COMPAT is not set
CONFIG_HIGHMEM=y
CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART=y
+CONFIG_USE_OF=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CPU_FREQ=y
@@ -145,16 +148,25 @@ CONFIG_IP_NF_MATCH_ECN=y
CONFIG_IP_NF_MATCH_TTL=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_REJECT_SKERR=y
CONFIG_IP_NF_TARGET_LOG=y
CONFIG_NF_NAT=y
CONFIG_IP_NF_TARGET_MASQUERADE=y
CONFIG_IP_NF_TARGET_NETMAP=y
CONFIG_IP_NF_TARGET_REDIRECT=y
CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_TARGET_LOG=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_TARGET_REJECT_SKERR=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
CONFIG_NET_SCH_INGRESS=y
@@ -187,6 +199,7 @@ CONFIG_CAIF=y
CONFIG_NFC=y
CONFIG_PN544_NFC=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_MISC_DEVICES=y
CONFIG_AD525X_DPOT=y
@@ -194,7 +207,6 @@ CONFIG_AD525X_DPOT_I2C=y
CONFIG_APDS9802ALS=y
CONFIG_SENSORS_NCT1008=y
CONFIG_UID_STAT=y
-# CONFIG_BCM4329_RFKILL is not set
CONFIG_TEGRA_CRYPTO_DEV=y
CONFIG_MAX1749_VIBRATOR=y
CONFIG_EEPROM_AT24=y
@@ -223,6 +235,7 @@ 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
CONFIG_BCM4329_FIRST_SCAN=y
@@ -325,6 +338,7 @@ CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_MAX8973=y
CONFIG_REGULATOR_MAX77663=y
CONFIG_REGULATOR_RC5T583=y
+CONFIG_REGULATOR_TPS51632=y
CONFIG_REGULATOR_TPS6586X=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TPS62360=y
@@ -372,6 +386,7 @@ CONFIG_SND_HDA_PLATFORM_DRIVER=y
CONFIG_SND_HDA_PLATFORM_NVIDIA_TEGRA=y
CONFIG_SND_HDA_POWER_SAVE=y
CONFIG_SND_HDA_POWER_SAVE_DEFAULT=10
+CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_TEGRA=y
CONFIG_SND_SOC_TEGRA_WM8903=y
@@ -379,12 +394,15 @@ CONFIG_SND_SOC_TEGRA_MAX98088=y
CONFIG_SND_SOC_TEGRA_TLV320AIC326X=y
CONFIG_SND_SOC_TEGRA_RT5639=y
CONFIG_SND_SOC_TEGRA_RT5640=y
+CONFIG_SND_SOC_TLV320AIC326X=y
+CONFIG_AIC3262_CODEC=y
CONFIG_HID_SONY=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICEFS=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_OTG=y
# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_ACM=y
CONFIG_USB_WDM=y
@@ -452,7 +470,6 @@ 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
CONFIG_SCHEDSTATS=y
@@ -460,6 +477,10 @@ CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_VM=y
+CONFIG_FAULT_INJECTION=y
+CONFIG_FAILSLAB=y
+CONFIG_FAULT_INJECTION_DEBUG_FS=y
+CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_FUNCTION_TRACER=y
# CONFIG_FUNCTION_GRAPH_TRACER is not set
CONFIG_TRACEDUMP=y
diff --git a/arch/arm/configs/tegra3_defconfig b/arch/arm/configs/tegra3_defconfig
index 86d74c113a23..41c39818ee70 100644
--- a/arch/arm/configs/tegra3_defconfig
+++ b/arch/arm/configs/tegra3_defconfig
@@ -27,9 +27,7 @@ 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_TEGRA_IRDA=y
CONFIG_MACH_CARDHU=y
CONFIG_MACH_TEGRA_ENTERPRISE=y
CONFIG_TEGRA_PWM=y
@@ -47,6 +45,8 @@ CONFIG_ARM_ERRATA_742230=y
CONFIG_ARM_ERRATA_743622=y
CONFIG_ARM_ERRATA_751472=y
CONFIG_ARM_ERRATA_752520=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEASPM_POWERSAVE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
@@ -184,6 +184,8 @@ CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIUART_LL=y
CONFIG_BT_BLUESLEEP=y
CONFIG_CFG80211=y
+CONFIG_LIB80211=m
+CONFIG_MAC80211=m
CONFIG_RFKILL=y
CONFIG_CAIF=y
CONFIG_NFC=y
@@ -230,7 +232,8 @@ CONFIG_BCM4329_WIFI_CONTROL_FUNC=y
CONFIG_BCMDHD=m
CONFIG_BCMDHD_FW_DIR="/lib/firmware"
CONFIG_BCMDHD_NVRAM_DIR="/lib/firmware"
-CONFIG_BCMDHD_WEXT=y
+CONFIG_DHD_ENABLE_P2P=y
+CONFIG_BCMDHD_CFG80211=y
CONFIG_BCMDHD_WIFI_CONTROL_FUNC=y
CONFIG_BCMDHD_HW_OOB=y
CONFIG_USB_CATC=y
@@ -357,6 +360,7 @@ CONFIG_USB_DEVICEFS=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_OTG=y
# CONFIG_USB_OTG_WHITELIST is not set
+CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_ACM=y
CONFIG_USB_WDM=y
diff --git a/arch/arm/configs/tegra_android_defconfig b/arch/arm/configs/tegra_android_defconfig
index eb6abec87b70..fb5ae2a1d999 100644
--- a/arch/arm/configs/tegra_android_defconfig
+++ b/arch/arm/configs/tegra_android_defconfig
@@ -48,6 +48,7 @@ CONFIG_PREEMPT=y
CONFIG_AEABI=y
# CONFIG_OABI_COMPAT is not set
CONFIG_HIGHMEM=y
+CONFIG_USE_OF=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CPU_FREQ=y
@@ -172,6 +173,7 @@ CONFIG_CFG80211=y
CONFIG_RFKILL=y
CONFIG_RFKILL_GPIO=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_MISC_DEVICES=y
CONFIG_AD525X_DPOT=y
diff --git a/arch/arm/configs/tegra_e1853_gnu_linux_defconfig b/arch/arm/configs/tegra_e1853_gnu_linux_defconfig
new file mode 100644
index 000000000000..8272a7e46d96
--- /dev/null
+++ b/arch/arm/configs/tegra_e1853_gnu_linux_defconfig
@@ -0,0 +1,219 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="arm-eabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=10
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_TEGRA_PCI=y
+CONFIG_MACH_E1853=y
+CONFIG_TEGRA_PWM=y
+CONFIG_TEGRA_TDM=y
+# CONFIG_TEGRA_CPU_DVFS is not set
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+# CONFIG_TEGRA_MC_EARLY_ACK is not set
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=448@2048M console=ttyS0,115200n8 earlyprintk init=/bin/ash"
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_NOR_TEGRA=y
+CONFIG_MTD_NAND_TEGRA=y
+CONFIG_MTD_NAND=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC75XX=y
+CONFIG_USB_NET_SMSC95XX=y
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_TEGRA=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SLAVE_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PDA_POWER=y
+CONFIG_BATTERY_BQ20Z75=y
+CONFIG_MFD_TPS6591X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA30_DAM=y
+CONFIG_SND_SOC_TEGRA30_I2S=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_TEGRA_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+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
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/configs/tegra_p1852_android_defconfig b/arch/arm/configs/tegra_p1852_android_defconfig
new file mode 100644
index 000000000000..4550c9ec6405
--- /dev/null
+++ b/arch/arm/configs/tegra_p1852_android_defconfig
@@ -0,0 +1,339 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="arm-eabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=10
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_ARCH_TEGRA_3x_SOC=y
+CONFIG_MACH_P1852=y
+CONFIG_TEGRA_DEBUG_UARTB=y
+CONFIG_TEGRA_PWM=y
+# CONFIG_TEGRA_CPU_DVFS is not set
+CONFIG_TEGRA_CLOCK_DEBUG_WRITE=y
+CONFIG_USB_HOTPLUG=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NETFILTER_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_NAND_TEGRA=y
+CONFIG_MTD_NAND=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_MISC_DEVICES=y
+CONFIG_AD525X_DPOT=y
+CONFIG_AD525X_DPOT_I2C=y
+CONFIG_APDS9802ALS=y
+CONFIG_SENSORS_NCT1008=y
+CONFIG_UID_STAT=y
+CONFIG_BCM4329_RFKILL=y
+CONFIG_TEGRA_CRYPTO_DEV=y
+CONFIG_MAX1749_VIBRATOR=y
+CONFIG_EEPROM_AT24=y
+CONFIG_TI_ST=y
+CONFIG_ST_GPS=m
+CONFIG_MPU_SENSORS_TIMERIRQ=y
+CONFIG_MPU_SENSORS_MPU3050=m
+CONFIG_MPU_SENSORS_MPU6050B1=m
+CONFIG_MPU_SENSORS_KXTF9=m
+CONFIG_MPU_SENSORS_MPU6050_ACCEL=m
+CONFIG_MPU_SENSORS_AK8963=m
+CONFIG_MPU_SENSORS_AK8975=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC75XX=y
+CONFIG_USB_NET_SMSC95XX=y
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+CONFIG_USB_NET_RAW_IP=y
+CONFIG_PPP=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_TEGRA=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SLAVE_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PDA_POWER=y
+CONFIG_BATTERY_BQ20Z75=y
+CONFIG_BATTERY_BQ27x00=y
+CONFIG_CHARGER_SMB349=y
+CONFIG_BATTERY_MAX17048=y
+CONFIG_CHARGER_GPIO=y
+CONFIG_SENSORS_TEGRA_TSENSOR=y
+CONFIG_SENSORS_INA219=y
+CONFIG_THERMAL=y
+CONFIG_MFD_TPS6586X=y
+CONFIG_MFD_TPS65910=y
+CONFIG_MFD_MAX77663=y
+CONFIG_MFD_TPS6591X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_P1852=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_WDM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_SERIAL_OPTION=y
+CONFIG_USB_SERIAL_BASEBAND=m
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_TEGRA=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_USB_TEGRA_OTG=y
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+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_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ANDROID_LOGGER=y
+CONFIG_ANDROID_RAM_CONSOLE=y
+CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y
+CONFIG_ANDROID_TIMED_GPIO=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
index 7a1435a4024a..7e4f4ab3e750 100644
--- a/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
+++ b/arch/arm/configs/tegra_p1852_gnu_linux_defconfig
@@ -35,6 +35,8 @@ 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_TEGRA_SE_ON_CBUS is not set
+CONFIG_TEGRA_CBUS_CLOCK_DIVIDER=1
CONFIG_NON_ALIASED_COHERENT_MEM=y
CONFIG_ARM_ERRATA_742230=y
CONFIG_ARM_ERRATA_743622=y
@@ -190,6 +192,8 @@ CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT4_FS=y
# CONFIG_DNOTIFY is not set
CONFIG_FUSE_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
# CONFIG_MISC_FILESYSTEMS is not set
diff --git a/arch/arm/configs/tegra_p1852_mods_defconfig b/arch/arm/configs/tegra_p1852_mods_defconfig
new file mode 100644
index 000000000000..9b8d758d5787
--- /dev/null
+++ b/arch/arm/configs/tegra_p1852_mods_defconfig
@@ -0,0 +1,206 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="arm-eabi-"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_PANIC_TIMEOUT=10
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_ELF_CORE is not set
+CONFIG_ASHMEM=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_TEGRA=y
+CONFIG_GPIO_PCA953X=y
+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_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_752520=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=448@2048M console=ttyS0,115200n8 earlyprintk init=/bin/ash"
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_TUNNEL=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_ANDROID_PARANOID_NETWORK is not set
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_NOR_TEGRA=y
+CONFIG_MTD_NAND_TEGRA=y
+CONFIG_MTD_NAND=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_MII=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_TEGRA=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_TEGRA=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_I2C_TEGRA=y
+CONFIG_SPI=y
+CONFIG_SPI_TEGRA=y
+CONFIG_SPI_SLAVE_TEGRA=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_BQ20Z75=y
+CONFIG_MFD_TPS6591X=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_TPS6591X=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_TEGRA_AVP is not set
+# CONFIG_TEGRA_MEDIASERVER is not set
+CONFIG_TEGRA_NVAVP=y
+# CONFIG_VGA_ARB is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_TEGRA_GRHOST=y
+CONFIG_TEGRA_DC=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_TEGRA=y
+CONFIG_SND_SOC_TEGRA_P1852=y
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+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
+CONFIG_SWITCH=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_TEGRA=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FUSE_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_EFI_PARTITION=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_TWOFISH=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_CCITT=y
+CONFIG_LIBCRC32C=y
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index 4d88425a4169..6b7f60c9b944 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -1,23 +1,77 @@
+/*
+ * arch/arm/include/asm/bug.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/>.
+ */
#ifndef _ASMARM_BUG_H
#define _ASMARM_BUG_H
#ifdef CONFIG_BUG
+
+/*
+ * Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
+ * We need to be careful not to conflict with those used by other modules and
+ * the register_undef_hook() system.
+ */
+#ifdef CONFIG_THUMB2_KERNEL
+#define BUG_INSTR_VALUE 0xde02
+#define BUG_INSTR_TYPE ".hword "
+#else
+#define BUG_INSTR_VALUE 0xe7f001f2
+#define BUG_INSTR_TYPE ".word "
+#endif
+
+
+#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE)
+#define _BUG(file, line, value) __BUG(file, line, value)
+
#ifdef CONFIG_DEBUG_BUGVERBOSE
-extern void __bug(const char *file, int line) __attribute__((noreturn));
-/* give file/line information */
-#define BUG() __bug(__FILE__, __LINE__)
+/*
+ * The extra indirection is to ensure that the __FILE__ string comes through
+ * OK. Many version of gcc do not support the asm %c parameter which would be
+ * preferable to this unpleasantness. We use mergeable string sections to
+ * avoid multiple copies of the string appearing in the kernel image.
+ */
-#else
+#define __BUG(__file, __line, __value) \
+do { \
+ BUILD_BUG_ON(sizeof(struct bug_entry) != 12); \
+ asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \
+ ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \
+ "2:\t.asciz " #__file "\n" \
+ ".popsection\n" \
+ ".pushsection __bug_table,\"a\"\n" \
+ "3:\t.word 1b, 2b\n" \
+ "\t.hword " #__line ", 0\n" \
+ ".popsection"); \
+ unreachable(); \
+} while (0)
-/* this just causes an oops */
-#define BUG() do { *(int *)0 = 0; } while (1)
+#else /* not CONFIG_DEBUG_BUGVERBOSE */
-#endif
+#define __BUG(__file, __line, __value) \
+do { \
+ asm volatile(BUG_INSTR_TYPE #__value); \
+ unreachable(); \
+} while (0)
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
#define HAVE_ARCH_BUG
-#endif
+#endif /* CONFIG_BUG */
#include <asm-generic/bug.h>
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index fd04f24055fd..22ec488494da 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -79,6 +79,7 @@
#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
#define REV_PL310_R2P0 4
+#define REV_PL310_R3P1_50 7
#ifndef __ASSEMBLY__
extern void l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
diff --git a/arch/arm/include/asm/mutex.h b/arch/arm/include/asm/mutex.h
index 93226cf23ae0..6e813d93a736 100644
--- a/arch/arm/include/asm/mutex.h
+++ b/arch/arm/include/asm/mutex.h
@@ -7,121 +7,15 @@
*/
#ifndef _ASM_MUTEX_H
#define _ASM_MUTEX_H
-
-#if __LINUX_ARM_ARCH__ < 6
-/* On pre-ARMv6 hardware the swp based implementation is the most efficient. */
-# include <asm-generic/mutex-xchg.h>
-#else
-
-/*
- * Attempting to lock a mutex on ARMv6+ can be done with a bastardized
- * atomic decrement (it is not a reliable atomic decrement but it satisfies
- * the defined semantics for our purpose, while being smaller and faster
- * than a real atomic decrement or atomic swap. The idea is to attempt
- * decrementing the lock value only once. If once decremented it isn't zero,
- * or if its store-back fails due to a dispute on the exclusive store, we
- * simply bail out immediately through the slow path where the lock will be
- * reattempted until it succeeds.
- */
-static inline void
-__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res;
-
- __asm__ (
-
- "ldrex %0, [%2] \n\t"
- "sub %0, %0, #1 \n\t"
- "strex %1, %0, [%2] "
-
- : "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
-
- __res |= __ex_flag;
- if (unlikely(__res != 0))
- fail_fn(count);
-}
-
-static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res;
-
- __asm__ (
-
- "ldrex %0, [%2] \n\t"
- "sub %0, %0, #1 \n\t"
- "strex %1, %0, [%2] "
-
- : "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
-
- __res |= __ex_flag;
- if (unlikely(__res != 0))
- __res = fail_fn(count);
- return __res;
-}
-
-/*
- * Same trick is used for the unlock fast path. However the original value,
- * rather than the result, is used to test for success in order to have
- * better generated assembly.
- */
-static inline void
-__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res, __orig;
-
- __asm__ (
-
- "ldrex %0, [%3] \n\t"
- "add %1, %0, #1 \n\t"
- "strex %2, %1, [%3] "
-
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
-
- __orig |= __ex_flag;
- if (unlikely(__orig != 0))
- fail_fn(count);
-}
-
/*
- * If the unlock was done on a contended lock, or if the unlock simply fails
- * then the mutex remains locked.
+ * On pre-ARMv6 hardware this results in a swp-based implementation,
+ * which is the most efficient. For ARMv6+, we have exclusive memory
+ * accessors and use atomic_dec to avoid the extra xchg operations
+ * on the locking slowpaths.
*/
-#define __mutex_slowpath_needs_to_unlock() 1
-
-/*
- * For __mutex_fastpath_trylock we use another construct which could be
- * described as a "single value cmpxchg".
- *
- * This provides the needed trylock semantics like cmpxchg would, but it is
- * lighter and less generic than a true cmpxchg implementation.
- */
-static inline int
-__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
-{
- int __ex_flag, __res, __orig;
-
- __asm__ (
-
- "1: ldrex %0, [%3] \n\t"
- "subs %1, %0, #1 \n\t"
- "strexeq %2, %1, [%3] \n\t"
- "movlt %0, #0 \n\t"
- "cmpeq %2, #0 \n\t"
- "bgt 1b "
-
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&count->counter)
- : "cc", "memory" );
-
- return __orig;
-}
-
+#if __LINUX_ARM_ARCH__ < 6
+#include <asm-generic/mutex-xchg.h>
+#else
+#include <asm-generic/mutex-dec.h>
#endif
#endif
diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h
index d8387437ec5a..49c5e2d2972d 100644
--- a/arch/arm/include/asm/outercache.h
+++ b/arch/arm/include/asm/outercache.h
@@ -28,6 +28,7 @@ struct outer_cache_fns {
void (*clean_range)(unsigned long, unsigned long);
void (*flush_range)(unsigned long, unsigned long);
void (*flush_all)(void);
+ void (*clean_all)(void);
void (*inv_all)(void);
void (*disable)(void);
#ifdef CONFIG_OUTER_CACHE_SYNC
@@ -62,6 +63,12 @@ static inline void outer_flush_all(void)
outer_cache.flush_all();
}
+static inline void outer_clean_all(void)
+{
+ if (outer_cache.clean_all)
+ outer_cache.clean_all();
+}
+
static inline void outer_inv_all(void)
{
if (outer_cache.inv_all)
@@ -83,6 +90,7 @@ static inline void outer_clean_range(phys_addr_t start, phys_addr_t end)
static inline void outer_flush_range(phys_addr_t start, phys_addr_t end)
{ }
static inline void outer_flush_all(void) { }
+static inline void outer_clean_all(void) { }
static inline void outer_inv_all(void) { }
static inline void outer_disable(void) { }
diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c
index 1a33e9d6bb1f..e855fcb71bf9 100644
--- a/arch/arm/kernel/devtree.c
+++ b/arch/arm/kernel/devtree.c
@@ -75,6 +75,9 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
unsigned int score, mdesc_score = ~1;
unsigned long dt_root;
const char *model;
+ __be32 *serial_prop;
+ u64 serial = 0;
+ unsigned long len;
if (!dt_phys)
return NULL;
@@ -118,7 +121,16 @@ struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
model = of_get_flat_dt_prop(dt_root, "compatible", NULL);
if (!model)
model = "<unknown>";
- pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);
+
+ serial_prop = of_get_flat_dt_prop(dt_root, "serial-num", &len);
+ if (serial_prop) {
+ serial = of_read_number(serial_prop, len / 4);
+ }
+ system_serial_high = serial >> 32;
+ system_serial_low = serial;
+
+ pr_info("Machine: %s, model: %s, serial: %llu\n", mdesc_best->name,
+ model, serial);
/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index bdfb37c59531..016473c1d794 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -280,8 +280,6 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
- printk("CPU%u: Booted secondary processor\n", cpu);
-
/*
* All kernel threads share the same mm context; grab a
* reference and switch to it.
@@ -314,6 +312,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
* before we continue.
*/
set_cpu_online(cpu, true);
+ printk("CPU%u: Booted secondary processor\n", cpu);
/*
* Setup the percpu timer for this CPU.
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 4ef9f0d04e5a..2534d2a1a164 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -4,6 +4,8 @@
* Copyright (C) 1995-2009 Russell King
* Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds
*
+ * 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
* published by the Free Software Foundation.
@@ -21,6 +23,7 @@
#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/kexec.h>
+#include <linux/bug.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/sched.h>
@@ -270,6 +273,8 @@ void die(const char *str, struct pt_regs *regs, int err)
spin_lock_irq(&die_lock);
console_verbose();
bust_spinlocks(1);
+ if (!user_mode(regs))
+ report_bug(regs->ARM_pc, regs);
ret = __die(str, err, thread, regs);
if (regs && kexec_should_crash(thread->task))
@@ -301,6 +306,24 @@ void arm_notify_die(const char *str, struct pt_regs *regs,
}
}
+#ifdef CONFIG_GENERIC_BUG
+
+int is_valid_bugaddr(unsigned long pc)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+ unsigned short bkpt;
+#else
+ unsigned long bkpt;
+#endif
+
+ if (probe_kernel_address((unsigned *)pc, bkpt))
+ return 0;
+
+ return bkpt == BUG_INSTR_VALUE;
+}
+
+#endif
+
static LIST_HEAD(undef_hook);
static DEFINE_SPINLOCK(undef_lock);
@@ -708,16 +731,6 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
arm_notify_die("unknown data abort code", regs, &info, instr, 0);
}
-void __attribute__((noreturn)) __bug(const char *file, int line)
-{
- printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
- *(int *)0 = 0;
-
- /* Avoid "noreturn function does return" */
- for (;;);
-}
-EXPORT_SYMBOL(__bug);
-
void __readwrite_bug(const char *fn)
{
printk("%s called, but not implemented\n", fn);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 4e66f62b8d41..1719a8ccde9c 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -1,3 +1,21 @@
+/*
+ * arch/arm/kernel/vmlinux.lds.S
+ *
+ * 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/>.
+ */
+
/* ld script to make ARM Linux kernel
* taken from the i386 version by Russell King
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
@@ -21,7 +39,8 @@
#define ARM_CPU_KEEP(x)
#endif
-#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)
+#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
+ defined(CONFIG_GENERIC_BUG)
#define ARM_EXIT_KEEP(x) x
#define ARM_EXIT_DISCARD(x)
#else
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 00e4c30783ef..243c33665641 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -1,3 +1,17 @@
+# 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/>.
+
if ARCH_TEGRA
comment "NVIDIA Tegra options"
@@ -53,6 +67,7 @@ config ARCH_TEGRA_3x_SOC
select CPA
select ARCH_HAS_SUSPEND_PAGETABLE
select NVMAP_CACHE_MAINT_BY_SET_WAYS
+ select PL310_ERRATA_727915
help
Support for NVIDIA Tegra 3 family of SoCs, based upon the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -76,6 +91,14 @@ config TEGRA_PCI
help
Adds PCIe Host controller driver for tegra based systems
+config TEGRA_IRDA
+ bool "IRDA on UARTB Port of Verbier"
+ select IRDA_CPLD
+ depends on ARCH_TEGRA_3x_SOC && MACH_CARDHU
+ help
+ Adds support for Vishay IrDA transceiver at UARTB port
+ of Verbier Boards(E1186 and E1198) with no ULPI rework done.
+
comment "Tegra board type"
config MACH_COLIBRI_T20
@@ -177,6 +200,12 @@ config MACH_P1852
help
Support for NVIDIA P1852 development platform
+config MACH_E1853
+ bool "E1853 board"
+ depends on ARCH_TEGRA_3x_SOC
+ help
+ Support for NVIDIA E1853 development platform
+
config MACH_TEGRA_ENTERPRISE
bool "Enterprise board"
depends on ARCH_TEGRA_3x_SOC
@@ -186,6 +215,12 @@ config MACH_TEGRA_ENTERPRISE
help
Support for NVIDIA Enterprise development platform
+config MACH_TAI
+ bool "Tai board"
+ depends on MACH_TEGRA_ENTERPRISE
+ help
+ Support for NVIDIA Tai development platform
+
config MACH_KAI
bool "Kai board"
depends on ARCH_TEGRA_3x_SOC
@@ -276,6 +311,13 @@ config TEGRA_P1852_TDM
Enables TDM mode driver for P1852 SKUs. If this
is not defined then I2S mode is selected by default.
+config TEGRA_TDM
+ bool "Enable TDM mode for Automotive SKUs"
+ depends on MACH_E1853
+ help
+ Enables TDM mode driver for Automotive 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
@@ -422,6 +464,16 @@ config TEGRA_EMC_TO_DDR_CLOCK
default "2" if ARCH_TEGRA_2x_SOC
default "1"
+config TEGRA_SE_ON_CBUS
+ bool "To Drive SE clock from cbus"
+ default y
+ help
+ This option enables SE clock to be derived from cbus
+
+config TEGRA_CBUS_CLOCK_DIVIDER
+ int "CBUS clock divider"
+ default "2"
+
config TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
bool "Use conservative cpu frequency governor when device enters early suspend"
depends on HAS_EARLYSUSPEND && CPU_FREQ
@@ -543,4 +595,20 @@ config TEGRA_SKIN_THROTTLE
help
Enable throttling to control the temperature of the skin/case
of the device.
+
+config TEGRA_LP1_950
+ bool "LP1 low core voltage"
+ default n
+ depends on ARCH_TEGRA_3x_SOC
+ help
+ Enable support for LP1 Core voltage to set to lowest
endif
+
+config TEGRA_DC_USE_HW_BPP
+ bool "Default Bits Per Pixel value from tegra DC hardware"
+ depends on TEGRA_DC
+ default n
+ help
+ Programs platform data to inform DC driver to use current
+ hardware value for bits per pixel setting. Useful for
+ preserving and displaying framebuffer content from bootloader.
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index c1a76685c31d..9a476876374a 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -19,6 +19,7 @@ obj-y += tegra2_clocks.o
obj-y += timer-t2.o
else
obj-y += tegra3_clocks.o
+obj-$(CONFIG_DEBUG_FS) += clocks_stats.o
obj-y += timer-t3.o
endif
obj-y += pinmux.o
@@ -38,7 +39,7 @@ 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
+obj-y += tegra_fuse.o
obj-y += kfuse.o
obj-y += csi.o
obj-$(CONFIG_TEGRA_SILICON_PLATFORM) += tegra_odm_fuses.o
@@ -171,6 +172,7 @@ obj-${CONFIG_MACH_WHISTLER} += board-whistler-memory.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-kbc.o
+obj-${CONFIG_MACH_CARDHU} += board-cardhu-irda.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-panel.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-pinmux.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-power.o
@@ -195,6 +197,11 @@ obj-${CONFIG_MACH_P1852} += board-p1852-panel.o
obj-${CONFIG_MACH_P1852} += board-p1852-pinmux.o
obj-${CONFIG_MACH_P1852} += board-p1852-sdhci.o
+obj-${CONFIG_MACH_E1853} += board-e1853.o
+obj-${CONFIG_MACH_E1853} += board-e1853-panel.o
+obj-${CONFIG_MACH_E1853} += board-e1853-pinmux.o
+obj-${CONFIG_MACH_E1853} += board-e1853-sdhci.o
+
obj-${CONFIG_MACH_TEGRA_ENTERPRISE} += board-enterprise.o
obj-${CONFIG_MACH_TEGRA_ENTERPRISE} += board-enterprise-panel.o
obj-${CONFIG_MACH_TEGRA_ENTERPRISE} += board-enterprise-pinmux.o
diff --git a/arch/arm/mach-tegra/Makefile.boot b/arch/arm/mach-tegra/Makefile.boot
index d8cb9173cdf7..6ca6212c711a 100644
--- a/arch/arm/mach-tegra/Makefile.boot
+++ b/arch/arm/mach-tegra/Makefile.boot
@@ -6,5 +6,9 @@ zreladdr-$(CONFIG_ARCH_TEGRA_3x_SOC) := 0x80008000
params_phys-$(CONFIG_ARCH_TEGRA_3x_SOC) := 0x80000100
initrd_phys-$(CONFIG_ARCH_TEGRA_3x_SOC) := 0x80800000
-dtb-$(CONFIG_MACH_HARMONY) += tegra-harmony.dtb
-dtb-$(CONFIG_MACH_SEABOARD) += tegra-seaboard.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-harmony.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-seaboard.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-ventana.dtb
+dtb-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20-whistler.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-cardhu.dtb
+dtb-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30-enterprise.dtb
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c
index 36f5fc6611f9..59e0779047b9 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/baseband-xmm-power.c
*
- * Copyright (C) 2011 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
@@ -51,8 +51,6 @@ EXPORT_SYMBOL(modem_flash);
unsigned long modem_pm = 1;
EXPORT_SYMBOL(modem_pm);
-unsigned long enum_delay_ms = 1000; /* ignored if !modem_flash */
-
module_param(modem_ver, ulong, 0644);
MODULE_PARM_DESC(modem_ver,
"baseband xmm power - modem software version");
@@ -62,50 +60,39 @@ MODULE_PARM_DESC(modem_flash,
module_param(modem_pm, ulong, 0644);
MODULE_PARM_DESC(modem_pm,
"baseband xmm power - modem power management (1 = pm, 0 = no pm)");
-module_param(enum_delay_ms, ulong, 0644);
-MODULE_PARM_DESC(enum_delay_ms,
- "baseband xmm power - delay in ms between modem on and enumeration");
static struct usb_device_id xmm_pm_ids[] = {
{ USB_DEVICE(VENDOR_ID, PRODUCT_ID),
.driver_info = 0 },
{}
};
-
+MODULE_DEVICE_TABLE(usb, xmm_pm_ids);
static struct gpio tegra_baseband_gpios[] = {
{ -1, GPIOF_OUT_INIT_LOW, "BB_RSTn" },
{ -1, GPIOF_OUT_INIT_LOW, "BB_ON" },
{ -1, GPIOF_OUT_INIT_LOW, "IPC_BB_WAKE" },
{ -1, GPIOF_IN, "IPC_AP_WAKE" },
- { -1, GPIOF_OUT_INIT_HIGH, "IPC_HSIC_ACTIVE" },
+ { -1, GPIOF_OUT_INIT_LOW, "IPC_HSIC_ACTIVE" },
{ -1, GPIOF_IN, "IPC_HSIC_SUS_REQ" },
};
-static enum {
- IPC_AP_WAKE_UNINIT,
- IPC_AP_WAKE_IRQ_READY,
- IPC_AP_WAKE_INIT1,
- IPC_AP_WAKE_INIT2,
- IPC_AP_WAKE_L,
- IPC_AP_WAKE_H,
-} ipc_ap_wake_state;
-
static enum baseband_xmm_powerstate_t baseband_xmm_powerstate;
+static enum ipc_ap_wake_state_t ipc_ap_wake_state;
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 work_struct l2_resume_work;
static struct work_struct autopm_resume_work;
static bool register_hsic_device;
static struct wake_lock wakelock;
static struct usb_device *usbdev;
-static bool CP_initiated_L2toL0;
+static bool cp_initiated_l2tol0;
static bool modem_power_on;
static int power_onoff;
static int reenable_autosuspend;
static bool wakeup_pending;
static bool modem_sleep_flag;
+static bool modem_acked_resume;
static spinlock_t xmm_lock;
static DEFINE_MUTEX(xmm_onoff_mutex);
static bool system_suspending;
@@ -178,6 +165,17 @@ static int tegra_baseband_rail_off(void)
return 0;
}
+static inline enum baseband_xmm_powerstate_t baseband_xmm_get_power_status(void)
+{
+ enum baseband_xmm_powerstate_t status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xmm_lock, flags);
+ status = baseband_xmm_powerstate;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ return status;
+}
+
static int baseband_modem_power_on(struct baseband_power_platform_data *data)
{
/* set IPC_HSIC_ACTIVE active */
@@ -227,11 +225,24 @@ static int baseband_modem_power_on_async(
return 0;
}
+static void xmm_power_reset_on(struct baseband_power_platform_data *pdata)
+{
+ /* reset / power on sequence */
+ gpio_set_value(pdata->modem.xmm.bb_rst, 0);
+ msleep(40);
+ gpio_set_value(pdata->modem.xmm.bb_rst, 1);
+ usleep_range(1000, 1100);
+ gpio_set_value(pdata->modem.xmm.bb_on, 1);
+ udelay(70);
+ gpio_set_value(pdata->modem.xmm.bb_on, 0);
+}
+
static int xmm_power_on(struct platform_device *device)
{
struct baseband_power_platform_data *pdata =
device->dev.platform_data;
struct xmm_power_data *data = &xmm_power_drv_data;
+ unsigned long flags;
int ret;
pr_debug("%s {\n", __func__);
@@ -241,15 +252,15 @@ static int xmm_power_on(struct platform_device *device)
pr_err("%s: !pdata\n", __func__);
return -EINVAL;
}
- if (baseband_xmm_powerstate != BBXMM_PS_UNINIT)
+ if (baseband_xmm_get_power_status() != BBXMM_PS_UNINIT)
return -EINVAL;
tegra_baseband_rail_on();
/* reset the state machine */
- baseband_xmm_powerstate = BBXMM_PS_INIT;
+ baseband_xmm_set_power_status(BBXMM_PS_INIT);
modem_sleep_flag = false;
- ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
+ modem_acked_resume = true;
pr_debug("%s wake_st(%d) modem version %lu\n", __func__,
ipc_ap_wake_state, modem_ver);
@@ -257,6 +268,11 @@ static int xmm_power_on(struct platform_device *device)
/* register usb host controller */
if (!modem_flash) {
pr_debug("%s - %d\n", __func__, __LINE__);
+
+ spin_lock_irqsave(&xmm_lock, flags);
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+
/* register usb host controller only once */
if (register_hsic_device) {
pr_debug("%s: register usb host controller\n",
@@ -277,7 +293,22 @@ static int xmm_power_on(struct platform_device *device)
__func__);
baseband_modem_power_on_async(pdata);
}
+ } else {
+ /* reset flashed modem then it will respond with
+ * ap-wake rising followed by falling gpio
+ */
+
+ pr_debug("%s: reset flash modem\n", __func__);
+
+ modem_power_on = false;
+ spin_lock_irqsave(&xmm_lock, flags);
+ ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
+
+ xmm_power_reset_on(pdata);
}
+
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__);
@@ -291,14 +322,14 @@ static int xmm_power_off(struct platform_device *device)
struct baseband_power_platform_data *pdata =
device->dev.platform_data;
struct xmm_power_data *data = &xmm_power_drv_data;
-
int ret;
unsigned long flags;
pr_debug("%s {\n", __func__);
- if (baseband_xmm_powerstate == BBXMM_PS_UNINIT)
+ if (baseband_xmm_get_power_status() == BBXMM_PS_UNINIT)
return -EINVAL;
+
/* check for device / platform data */
if (!device) {
pr_err("%s: !device\n", __func__);
@@ -309,18 +340,20 @@ static int xmm_power_off(struct platform_device *device)
return -EINVAL;
}
+ spin_lock_irqsave(&xmm_lock, flags);
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
+ spin_unlock_irqrestore(&xmm_lock, flags);
+
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 (pdata->hsic_unregister)
- pdata->hsic_unregister(data->hsic_device);
+ pdata->hsic_unregister(&data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
-
/* set IPC_HSIC_ACTIVE low */
gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
@@ -332,13 +365,15 @@ static int xmm_power_off(struct platform_device *device)
/* sleep 1ms */
usleep_range(1000, 2000);
- baseband_xmm_powerstate = BBXMM_PS_UNINIT;
- modem_sleep_flag = false;
- CP_initiated_L2toL0 = false;
+ baseband_xmm_set_power_status(BBXMM_PS_UNINIT);
+
spin_lock_irqsave(&xmm_lock, flags);
+ modem_sleep_flag = false;
+ cp_initiated_l2tol0 = false;
wakeup_pending = false;
system_suspending = false;
spin_unlock_irqrestore(&xmm_lock, flags);
+
/* start registration process once again on xmm on */
register_hsic_device = true;
@@ -419,73 +454,77 @@ static void xmm_power_l2_resume(void)
if (!pdata)
return;
+ /* erroneous remote-wakeup might call this from irq */
+ if (in_interrupt() || in_atomic()) {
+ pr_err("%s: not allowed in interrupt\n", __func__);
+ 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);
+ modem_sleep_flag = false;
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);
+ value = gpio_get_value(pdata->modem.xmm.ipc_ap_wake);
+ if (value) {
+ /* set the slave wakeup request - bb_wake high */
+ drv->hostwake = 0;
+ gpio_set_value(pdata->modem.xmm.ipc_bb_wake, 1);
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ pr_info("AP L2->L0\n");
retry:
- /* wait for cp */
- pr_debug("waiting for host wakeup from CP...\n");
- ret = wait_event_interruptible_timeout(drv->bb_wait,
+ /* 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) {
+ 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;
}
- 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");
+ pr_debug("%s: caught signal\n", __func__);
+ rcount++;
+ goto retry;
+ }
+ pr_debug("Get gpio host wakeup low <-\n");
+ } else {
+ cp_initiated_l2tol0 = false;
+ queue_work(workqueue, &l2_resume_work);
+ spin_unlock_irqrestore(&xmm_lock, flags);
+ pr_info("CP L2->L0\n");
}
}
-
+/* this function holds xmm_lock */
void baseband_xmm_set_power_status(unsigned int status)
{
struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
int value = 0;
unsigned long flags;
- if (baseband_xmm_powerstate == status)
+ if (baseband_xmm_get_power_status() == status)
return;
- pr_debug("%s\n", __func__);
+
+ /* avoid prints inside spinlock */
+ if (status <= BBXMM_PS_L2)
+ pr_info("%s\n", status == BBXMM_PS_L0 ? "L0" : "L2");
+
+ spin_lock_irqsave(&xmm_lock, flags);
switch (status) {
case BBXMM_PS_L0:
- if (modem_sleep_flag) {
- /* 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_timeout(&wakelock, HZ*2);
+
+ /* pull hsic_active high for enumeration */
value = gpio_get_value(data->modem.xmm.ipc_hsic_active);
- pr_debug("before L0 ipc_hsic_active=%d\n", value);
if (!value) {
pr_debug("L0 gpio set ipc_hsic_active=1 ->\n");
gpio_set_value(data->modem.xmm.ipc_hsic_active, 1);
@@ -494,33 +533,42 @@ void baseband_xmm_set_power_status(unsigned int status)
modem_power_on = false;
baseband_modem_power_on(data);
}
+
+ /* cp acknowledgment for ap L2->L0 wake */
+ if (!modem_acked_resume)
+ pr_err("%s: CP didn't ack usb-resume\n", __func__);
+ 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 bb_wake done low\n");
+ }
break;
case BBXMM_PS_L2:
- pr_info("L2\n");
- baseband_xmm_powerstate = status;
- spin_lock_irqsave(&xmm_lock, flags);
+ modem_acked_resume = false;
if (wakeup_pending) {
spin_unlock_irqrestore(&xmm_lock, flags);
pr_debug("%s: wakeup pending\n", __func__);
xmm_power_l2_resume();
+ spin_lock_irqsave(&xmm_lock, flags);
+ break;
} else {
- spin_unlock_irqrestore(&xmm_lock, flags);
if (wake_lock_active(&wakelock))
wake_unlock(&wakelock);
modem_sleep_flag = true;
}
+ baseband_xmm_powerstate = status;
break;
case BBXMM_PS_L2TOL0:
pr_debug("L2TOL0\n");
- spin_lock_irqsave(&xmm_lock, flags);
system_suspending = false;
wakeup_pending = false;
- spin_unlock_irqrestore(&xmm_lock, flags);
/* do this only from L2 state */
if (baseband_xmm_powerstate == BBXMM_PS_L2) {
baseband_xmm_powerstate = status;
- pr_debug("BB XMM POWER STATE = %d\n", status);
+ spin_unlock_irqrestore(&xmm_lock, flags);
xmm_power_l2_resume();
+ spin_lock_irqsave(&xmm_lock, flags);
}
baseband_xmm_powerstate = status;
break;
@@ -529,141 +577,109 @@ void baseband_xmm_set_power_status(unsigned int status)
baseband_xmm_powerstate = status;
break;
}
+ spin_unlock_irqrestore(&xmm_lock, flags);
pr_debug("BB XMM POWER STATE = %d\n", status);
}
EXPORT_SYMBOL_GPL(baseband_xmm_set_power_status);
-irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id)
+
+irqreturn_t xmm_power_ipc_ap_wake_irq(int value)
{
struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
struct xmm_power_data *drv = &xmm_power_drv_data;
- int value;
-
- 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);
-
- /* 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__);
- /* go to IPC_AP_WAKE_INIT1 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
- queue_work(workqueue, &init1_work);
- } else
- pr_debug("%s - IPC_AP_WAKE_INIT1"
- " - 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__);
- } 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(workqueue, &init2_work);
- }
- 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);
- }
+ spin_lock(&xmm_lock);
+
+ /* AP L2 to L0 wakeup */
+ 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;
+ spin_unlock(&xmm_lock);
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_L2) {
- CP_initiated_L2toL0 = true;
+ if (system_suspending)
+ pr_info("set wakeup_pending 1 in system_suspending\n");
+ else {
+ if (baseband_xmm_powerstate == BBXMM_PS_L2 ||
+ baseband_xmm_powerstate == BBXMM_PS_L2TOL0) {
+ 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);
- }
+ spin_lock(&xmm_lock);
+ } else
+ cp_initiated_l2tol0 = true;
+
}
+
/* save gpio state */
ipc_ap_wake_state = IPC_AP_WAKE_L;
+ spin_unlock(&xmm_lock);
} else {
pr_debug("%s - rising\n", __func__);
+ spin_lock(&xmm_lock);
+ modem_acked_resume = true;
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;
+ spin_unlock(&xmm_lock);
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;
+ spin_unlock(&xmm_lock);
}
-
return IRQ_HANDLED;
}
EXPORT_SYMBOL(xmm_power_ipc_ap_wake_irq);
-static void xmm_power_init1_work(struct work_struct *work)
+static irqreturn_t ipc_ap_wake_irq(int irq, void *dev_id)
{
- struct baseband_power_platform_data *pdata = xmm_power_drv_data.pdata;
+ struct baseband_power_platform_data *data = xmm_power_drv_data.pdata;
int value;
- pr_debug("%s {\n", __func__);
-
- /* check if IPC_HSIC_ACTIVE high */
- 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 */
- msleep(100);
-
- /* set IPC_HSIC_ACTIVE low */
- gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
-
- /* wait 10 ms */
- usleep_range(10000, 11000);
-
- /* set IPC_HSIC_ACTIVE high */
- gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
+ 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);
- /* wait 20 ms */
- msleep(20);
+ /* modem wakeup part */
+ if (likely(ipc_ap_wake_state >= IPC_AP_WAKE_INIT2))
+ return xmm_power_ipc_ap_wake_irq(value);
- pr_debug("%s }\n", __func__);
+ /* modem initialization/bootup part*/
+ 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) {
+ if (value) {
+ /* make state ready for falling edge */
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
+ pr_debug("%s - got rising edge\n", __func__);
+ }
+ } else if (ipc_ap_wake_state == IPC_AP_WAKE_INIT1) {
+ if (!value) {
+ pr_debug("%s - got falling edge at INIT1\n", __func__);
+ /* go to IPC_AP_WAKE_INIT2 state */
+ ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
+ queue_work(workqueue, &init2_work);
+ } else
+ pr_debug("%s - unexpected rising edge\n", __func__);
+ }
+ return IRQ_HANDLED;
}
static void xmm_power_init2_work(struct work_struct *work)
@@ -684,7 +700,6 @@ static void xmm_power_init2_work(struct work_struct *work)
pr_err("%s: hsic_register is missing\n", __func__);
register_hsic_device = false;
}
-
}
static void xmm_power_autopm_resume(struct work_struct *work)
@@ -724,19 +739,6 @@ static void xmm_power_l2_resume_work(struct work_struct *work)
pr_debug("} %s\n", __func__);
}
-static void xmm_power_reset_on(struct baseband_power_platform_data *pdata)
-{
- /* reset / power on sequence */
- gpio_set_value(pdata->modem.xmm.bb_rst, 0);
- msleep(40);
- 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(pdata->modem.xmm.bb_on, 0);
-}
-
-
static void xmm_power_work_func(struct work_struct *work)
{
struct xmm_power_data *data =
@@ -774,12 +776,12 @@ static void xmm_power_work_func(struct work_struct *work)
case BBXMM_WORK_INIT_FLASH_PM_STEP1:
pr_debug("BBXMM_WORK_INIT_FLASH_PM_STEP1\n");
pr_debug("%s: ipc_hsic_active -> 0\n", __func__);
- gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 1);
+ gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
+ modem_acked_resume = true;
/* reset / power on sequence */
xmm_power_reset_on(pdata);
/* set power status as on */
power_onoff = 1;
- gpio_set_value(pdata->modem.xmm.ipc_hsic_active, 0);
/* expecting init2 performs register hsic to enumerate modem
* software directly.
@@ -820,7 +822,7 @@ static void xmm_device_remove_handler(struct usb_device *udev)
if (usbdev == udev) {
pr_info("Remove device %d <%s %s>\n", udev->devnum,
udev->manufacturer, udev->product);
- usbdev = 0;
+ usbdev = NULL;
}
}
@@ -882,9 +884,9 @@ static int xmm_power_pm_notifier_event(struct notifier_block *this,
if (wakeup_pending &&
(baseband_xmm_powerstate == BBXMM_PS_L2)) {
wakeup_pending = false;
+ cp_initiated_l2tol0 = true;
spin_unlock_irqrestore(&xmm_lock, flags);
pr_info("%s : Service Pending CP wakeup\n", __func__);
- CP_initiated_L2toL0 = true;
baseband_xmm_set_power_status(BBXMM_PS_L2TOL0);
return NOTIFY_OK;
}
@@ -908,7 +910,6 @@ static int xmm_power_driver_probe(struct platform_device *device)
int err;
pr_debug("%s\n", __func__);
- pr_debug("[XMM] enum_delay_ms=%ld\n", enum_delay_ms);
/* check for platform data */
if (!pdata)
@@ -959,7 +960,7 @@ static int xmm_power_driver_probe(struct platform_device *device)
ipc_ap_wake_state = IPC_AP_WAKE_UNINIT;
err = request_threaded_irq(
gpio_to_irq(pdata->modem.xmm.ipc_ap_wake),
- NULL, xmm_power_ipc_ap_wake_irq,
+ NULL, ipc_ap_wake_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"IPC_AP_WAKE_IRQ", NULL);
if (err < 0) {
@@ -972,9 +973,9 @@ static int xmm_power_driver_probe(struct platform_device *device)
if (err < 0)
pr_err("%s: enable_irq_wake error\n", __func__);
- pr_debug("%s: AP_WAKE_INIT1\n", __func__);
- /* ver 1130 or later starts in INIT1 state */
- ipc_ap_wake_state = IPC_AP_WAKE_INIT1;
+ pr_debug("%s: set state IPC_AP_WAKE_IRQ_READY\n", __func__);
+ /* ver 1130 or later start in IRQ_READY state */
+ ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY;
}
/* init work queue */
@@ -989,15 +990,14 @@ static int xmm_power_driver_probe(struct platform_device *device)
queue_work(workqueue, &xmm_power_drv_data.work);
/* init work objects */
- 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(&l2_resume_work, xmm_power_l2_resume_work);
INIT_WORK(&autopm_resume_work, xmm_power_autopm_resume);
/* init state variables */
register_hsic_device = true;
- CP_initiated_L2toL0 = false;
- baseband_xmm_powerstate = BBXMM_PS_UNINIT;
+ cp_initiated_l2tol0 = false;
+ baseband_xmm_set_power_status(BBXMM_PS_UNINIT);
spin_lock_irqsave(&xmm_lock, flags);
wakeup_pending = false;
system_suspending = false;
@@ -1026,9 +1026,8 @@ static int xmm_power_driver_remove(struct platform_device *device)
usb_unregister_notify(&usb_xmm_nb);
/* free baseband irq(s) */
- if (modem_flash && modem_pm) {
+ if (modem_flash && modem_pm)
free_irq(gpio_to_irq(pdata->modem.xmm.ipc_ap_wake), NULL);
- }
/* free baseband gpio(s) */
gpio_free_array(tegra_baseband_gpios,
@@ -1042,7 +1041,7 @@ static int xmm_power_driver_remove(struct platform_device *device)
/* unregister usb host controller */
if (pdata->hsic_unregister)
- pdata->hsic_unregister(data->hsic_device);
+ pdata->hsic_unregister(&data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.h b/arch/arm/mach-tegra/baseband-xmm-power.h
index 69140891319d..55c81833ba04 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power.h
+++ b/arch/arm/mach-tegra/baseband-xmm-power.h
@@ -15,7 +15,7 @@
*/
#ifndef BASEBAND_XMM_POWER_H
-#define BASREBAND_XMM_POWER_H
+#define BASEBAND_XMM_POWER_H
#include <linux/pm.h>
#include <linux/suspend.h>
@@ -41,7 +41,7 @@ enum baseband_type {
struct baseband_power_platform_data {
enum baseband_type baseband_type;
struct platform_device* (*hsic_register)(void);
- void (*hsic_unregister)(struct platform_device *);
+ void (*hsic_unregister)(struct platform_device **);
union {
struct {
int mdm_reset;
@@ -90,21 +90,28 @@ struct xmm_power_data {
};
enum baseband_xmm_powerstate_t {
- BBXMM_PS_UNINIT = 0,
- BBXMM_PS_INIT = 1,
- BBXMM_PS_L0 = 2,
- BBXMM_PS_L0TOL2 = 3,
- BBXMM_PS_L2 = 4,
- BBXMM_PS_L2TOL0 = 5,
- BBXMM_PS_L2TOL3 = 6,
- BBXMM_PS_L3 = 7,
- BBXMM_PS_L3TOL0 = 8,
+ BBXMM_PS_L0 = 0,
+ BBXMM_PS_L2 = 1,
+ BBXMM_PS_L0TOL2 = 2,
+ BBXMM_PS_L2TOL0 = 3,
+ BBXMM_PS_UNINIT = 4,
+ BBXMM_PS_INIT = 5,
+ BBXMM_PS_L3 = 6,
BBXMM_PS_LAST = -1,
};
-irqreturn_t xmm_power_ipc_ap_wake_irq(int irq, void *dev_id);
+enum ipc_ap_wake_state_t {
+ IPC_AP_WAKE_UNINIT,
+ IPC_AP_WAKE_IRQ_READY,
+ IPC_AP_WAKE_INIT1,
+ IPC_AP_WAKE_INIT2,
+ IPC_AP_WAKE_L,
+ IPC_AP_WAKE_H,
+};
+
+irqreturn_t xmm_power_ipc_ap_wake_irq(int value);
void baseband_xmm_set_power_status(unsigned int status);
extern struct xmm_power_data xmm_power_drv_data;
-#endif /* BASREBAND_XMM_POWER_H */
+#endif /* BASEBAND_XMM_POWER_H */
diff --git a/arch/arm/mach-tegra/baseband-xmm-power2.c b/arch/arm/mach-tegra/baseband-xmm-power2.c
index 3c6285c0a070..a79cd6fb499f 100644
--- a/arch/arm/mach-tegra/baseband-xmm-power2.c
+++ b/arch/arm/mach-tegra/baseband-xmm-power2.c
@@ -49,16 +49,7 @@ MODULE_PARM_DESC(XYZ,
static struct workqueue_struct *workqueue;
static bool free_ipc_ap_wake_irq;
-
-static enum {
- IPC_AP_WAKE_UNINIT,
- IPC_AP_WAKE_IRQ_READY,
- IPC_AP_WAKE_INIT1,
- IPC_AP_WAKE_INIT2,
- IPC_AP_WAKE_L,
- IPC_AP_WAKE_H,
-} ipc_ap_wake_state;
-
+static enum ipc_ap_wake_state_t ipc_ap_wake_state;
static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
{
@@ -66,8 +57,6 @@ static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
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 (!pdata)
return IRQ_HANDLED;
@@ -79,8 +68,8 @@ static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
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__);
+ pr_debug("%s: IPC_AP_WAKE_IRQ_READY got falling edge\n",
+ __func__);
/* go to IPC_AP_WAKE_INIT2 state */
ipc_ap_wake_state = IPC_AP_WAKE_INIT2;
/* queue work */
@@ -88,7 +77,7 @@ static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
BBXMM_WORK_INIT_FLASHLESS_PM_STEP2;
queue_work(workqueue, &data->work);
} else
- pr_debug("%s: IPC_AP_WAKE_INIT1"
+ pr_debug("%s: IPC_AP_WAKE_IRQ_READY"
" wait for falling edge\n", __func__);
} else {
if (!value) {
@@ -98,7 +87,7 @@ static irqreturn_t xmm_power2_ipc_ap_wake_irq(int irq, void *dev_id)
pr_debug("%s - rising\n", __func__);
ipc_ap_wake_state = IPC_AP_WAKE_H;
}
- return xmm_power_ipc_ap_wake_irq(irq, dev_id);
+ return xmm_power_ipc_ap_wake_irq(value);
}
return IRQ_HANDLED;
@@ -119,7 +108,7 @@ static void xmm_power2_step1(struct work_struct *work)
/* unregister usb host controller */
if (pdata->hsic_unregister)
- pdata->hsic_unregister(data->hsic_device);
+ pdata->hsic_unregister(&data->hsic_device);
else
pr_err("%s: hsic_unregister is missing\n", __func__);
diff --git a/arch/arm/mach-tegra/board-aruba-panel.c b/arch/arm/mach-tegra/board-aruba-panel.c
index 01ade01a0eb6..488f212422e6 100644
--- a/arch/arm/mach-tegra/board-aruba-panel.c
+++ b/arch/arm/mach-tegra/board-aruba-panel.c
@@ -50,8 +50,6 @@ static int aruba_backlight_init(struct device *dev) {
ret = gpio_direction_output(aruba_bl_enb, 1);
if (ret < 0)
gpio_free(aruba_bl_enb);
- else
- tegra_gpio_enable(aruba_bl_enb);
return ret;
};
@@ -59,7 +57,6 @@ static int aruba_backlight_init(struct device *dev) {
static void aruba_backlight_exit(struct device *dev) {
gpio_set_value(aruba_bl_enb, 0);
gpio_free(aruba_bl_enb);
- tegra_gpio_disable(aruba_bl_enb);
}
static int aruba_backlight_notify(struct device *unused, int brightness)
diff --git a/arch/arm/mach-tegra/board-aruba-sdhci.c b/arch/arm/mach-tegra/board-aruba-sdhci.c
index 26b04a9021e1..cf29137b773f 100644
--- a/arch/arm/mach-tegra/board-aruba-sdhci.c
+++ b/arch/arm/mach-tegra/board-aruba-sdhci.c
@@ -224,9 +224,6 @@ static int __init aruba_wifi_init(void)
gpio_request(ARUBA_WLAN_PWR, "wlan_power");
gpio_request(ARUBA_WLAN_RST, "wlan_rst");
- tegra_gpio_enable(ARUBA_WLAN_PWR);
- tegra_gpio_enable(ARUBA_WLAN_RST);
-
gpio_direction_output(ARUBA_WLAN_PWR, 0);
gpio_direction_output(ARUBA_WLAN_RST, 0);
diff --git a/arch/arm/mach-tegra/board-aruba-sensors.c b/arch/arm/mach-tegra/board-aruba-sensors.c
index f5ba3d761634..34891ae6f6c2 100644
--- a/arch/arm/mach-tegra/board-aruba-sensors.c
+++ b/arch/arm/mach-tegra/board-aruba-sensors.c
@@ -43,14 +43,12 @@
static void aruba_isl29018_init(void)
{
- tegra_gpio_enable(ISL29018_IRQ_GPIO);
gpio_request(ISL29018_IRQ_GPIO, "isl29018");
gpio_direction_input(ISL29018_IRQ_GPIO);
}
static void aruba_akm8975_init(void)
{
- tegra_gpio_enable(AKM8975_IRQ_GPIO);
gpio_request(AKM8975_IRQ_GPIO, "akm8975");
gpio_direction_input(AKM8975_IRQ_GPIO);
}
diff --git a/arch/arm/mach-tegra/board-aruba.c b/arch/arm/mach-tegra/board-aruba.c
index 2fc524ccef93..bb47beeffbdc 100644
--- a/arch/arm/mach-tegra/board-aruba.c
+++ b/arch/arm/mach-tegra/board-aruba.c
@@ -459,14 +459,6 @@ static struct platform_device *aruba_devices[] __initdata = {
#endif
};
-static void aruba_keys_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(aruba_keys); i++)
- tegra_gpio_enable(aruba_keys[i].gpio);
-}
-
static int __init aruba_touch_init(void)
{
return 0;
@@ -518,7 +510,6 @@ static void __init tegra_aruba_init(void)
aruba_i2c_init();
aruba_regulator_init();
aruba_touch_init();
- aruba_keys_init();
aruba_usb_init();
aruba_panel_init();
aruba_sensors_init();
diff --git a/arch/arm/mach-tegra/board-cardhu-irda.c b/arch/arm/mach-tegra/board-cardhu-irda.c
new file mode 100644
index 000000000000..489d473fc08f
--- /dev/null
+++ b/arch/arm/mach-tegra/board-cardhu-irda.c
@@ -0,0 +1,178 @@
+/*
+ * arch/arm/mach-tegra/board-cardhu-irda.c
+ *
+ * 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.
+ */
+
+/* This driver tested with tfdu6103 irda transceiver */
+
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/serial_8250.h>
+#include <linux/tegra_uart.h>
+
+#include "gpio-names.h"
+#include "board-cardhu.h"
+#include "board.h"
+#include "devices.h"
+
+/* Uncomment the next line to get the function entry logs */
+/*#define DRV_FUNC 1*/
+
+#undef FPRINT
+#ifdef DRV_FUNC
+#define FPRINT(fmt, args...) printk(KERN_INFO "IRDA: " fmt, ## args)
+#else
+#define FPRINT(fmt, args...)
+#endif
+
+#define CARDHU_IRDA_SD TEGRA_GPIO_PJ6
+#define CARDHU_IRDA_TX TEGRA_GPIO_PC2
+#define CARDHU_IRDA_RX TEGRA_GPIO_PC3
+
+#define IRDA_DELAY 1
+
+#define SIR 1
+#define FIR 2
+#define VFIR 3 /* tfdu6108 doesn't support */
+
+
+static int irda_mode;
+
+/* If mode = SIR mode switch will be FIR -> SIR
+ If mode = FIR mode switch will be SIR ->FIR */
+
+static int cardhu_irda_mode_switch(int mode)
+{
+ int ret = -1;
+
+ FPRINT("Start of Func %s\n", __func__);
+
+ if ((mode != SIR) && (mode != FIR)) {
+ pr_err("Unsupported irda mode\n");
+ return ret;
+ }
+
+ gpio_set_value(CARDHU_IRDA_SD, 1);
+
+ udelay(IRDA_DELAY);
+
+ ret = gpio_request(CARDHU_IRDA_TX, "irda_tx");
+ if (ret < 0) {
+ pr_err("%s: cardhu_irda_tx gpio request failed %d\n",
+ __func__, ret);
+ gpio_set_value(CARDHU_IRDA_SD, 0);
+ return ret;
+ }
+
+ if (mode == SIR)
+ ret = gpio_direction_output(CARDHU_IRDA_TX, 0);
+ else if (mode == FIR)
+ ret = gpio_direction_output(CARDHU_IRDA_TX, 1);
+
+ if (ret) {
+ pr_err("%s: cardhu_irda_tx Direction configuration failed %d\n",
+ __func__, ret);
+ gpio_set_value(CARDHU_IRDA_SD, 0);
+ goto closure;
+ }
+
+ udelay(IRDA_DELAY);
+
+ gpio_set_value(CARDHU_IRDA_SD, 0);
+
+ udelay(IRDA_DELAY);
+
+ if (mode == FIR) {
+ gpio_set_value(CARDHU_IRDA_TX, 0);
+ irda_mode = FIR;
+ pr_info("IrDA Transceiver is switched to FIR mode\n");
+ } else {
+ pr_info("IrDA Transceiver is switched to SIR mode\n");
+ irda_mode = SIR;
+ }
+
+ udelay(IRDA_DELAY);
+
+closure:
+ gpio_free(CARDHU_IRDA_TX);
+ return ret;
+}
+
+static int SD_config(void)
+{
+ int ret = -1;
+
+ FPRINT("Start of the Func %s\n", __func__);
+ /* Gpio enable for SD */
+ ret = gpio_request(CARDHU_IRDA_SD, "irda_sd");
+ if (ret < 0) {
+ pr_err("%s: cardhu_irda_sd gpio request failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = gpio_direction_output(CARDHU_IRDA_SD, 1);
+ if (ret)
+ pr_err("%s: cardhu_irda_sd Direction configuration failed %d\n",
+ __func__, ret);
+ return ret;
+}
+
+static void cardhu_irda_start(void)
+{
+ FPRINT("Start of the Func %s\n", __func__);
+ pr_info("IrDA transceiver is enabled\n");
+ gpio_set_value(CARDHU_IRDA_SD, 0);
+ irda_mode = SIR;
+}
+
+static void cardhu_irda_shutdown(void)
+{
+ FPRINT("Start of the Func %s\n", __func__);
+ pr_info("IrDA transceiver is disabled\n");
+ /* Setting the IrDA transceiver into shutdown mode*/
+ gpio_set_value(CARDHU_IRDA_SD, 1);
+}
+
+static int cardhu_irda_init(void)
+{
+ int ret = 0;
+
+ FPRINT("Start of the Func %s\n", __func__);
+ if (SD_config() < 0) {
+ pr_err("%s: Error in IRDA_SD signal configuration\n", __func__);
+ ret = -1;
+ }
+ return ret;
+}
+
+static void cardhu_irda_remove(void)
+{
+ FPRINT("Start of the Func %s\n", __func__);
+ gpio_free(CARDHU_IRDA_SD);
+}
+
+
+struct tegra_uart_platform_data cardhu_irda_pdata = {
+ .is_irda = true,
+ .irda_init = cardhu_irda_init,
+ .irda_start = cardhu_irda_start,
+ .irda_mode_switch = cardhu_irda_mode_switch,
+ .irda_shutdown = cardhu_irda_shutdown,
+ .irda_remove = cardhu_irda_remove,
+};
diff --git a/arch/arm/mach-tegra/board-cardhu-kbc.c b/arch/arm/mach-tegra/board-cardhu-kbc.c
index c3971403148f..ce9b22cc1170 100644
--- a/arch/arm/mach-tegra/board-cardhu-kbc.c
+++ b/arch/arm/mach-tegra/board-cardhu-kbc.c
@@ -122,6 +122,17 @@ int __init cardhu_scroll_init(void)
.debounce_interval = 10, \
}
+#define GPIO_SW_KEY(_id, _gpio, _iswake) \
+ { \
+ .code = _id, \
+ .gpio = _gpio, \
+ .active_low = 1, \
+ .desc = #_id, \
+ .type = EV_SW, \
+ .wakeup = _iswake, \
+ .debounce_interval = 1, \
+ }
+
#define GPIO_IKEY(_id, _irq, _iswake, _deb) \
{ \
.code = _id, \
@@ -165,6 +176,7 @@ static struct gpio_keys_button cardhu_keys_e1291[] = {
[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),
+ [7] = GPIO_SW_KEY(SW_LID, TPS6591X_GPIO_5, 0),
};
static struct gpio_keys_button cardhu_keys_e1291_a04[] = {
@@ -176,6 +188,7 @@ static struct gpio_keys_button cardhu_keys_e1291_a04[] = {
[5] = GPIO_KEY(KEY_MENU, PQ1, 0),
[6] = GPIO_KEY(KEY_RESERVED, PV0, 1),
[7] = GPIO_IKEY(KEY_POWER, TPS6591X_IRQ_BASE + TPS6591X_INT_PWRON, 1, 100),
+ [8] = GPIO_SW_KEY(SW_LID, TPS6591X_GPIO_5, 0),
};
static struct gpio_keys_platform_data cardhu_keys_e1291_pdata = {
diff --git a/arch/arm/mach-tegra/board-cardhu-memory.c b/arch/arm/mach-tegra/board-cardhu-memory.c
index 1ed99a9fa1fa..4ec8839c44f6 100644
--- a/arch/arm/mach-tegra/board-cardhu-memory.c
+++ b/arch/arm/mach-tegra/board-cardhu-memory.c
@@ -705,7 +705,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000280, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0x00030003, /* MC_EMEM_ARB_CFG */
0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -825,7 +825,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -945,7 +945,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -1065,7 +1065,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -1185,8 +1185,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000174b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000005, /* MC_EMEM_ARB_CFG */
- 0x80000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000b, /* MC_EMEM_ARB_CFG */
+ 0xc0000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000009, /* MC_EMEM_ARB_TIMING_RC */
@@ -1305,8 +1305,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80001941, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000006, /* MC_EMEM_ARB_CFG */
- 0x8000004a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0xc000004a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x0000000a, /* MC_EMEM_ARB_TIMING_RC */
@@ -1425,8 +1425,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80001bc0, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000006, /* MC_EMEM_ARB_CFG */
- 0x80000051, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000d, /* MC_EMEM_ARB_CFG */
+ 0xc0000051, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
0x00000003, /* MC_EMEM_ARB_TIMING_RP */
0x0000000b, /* MC_EMEM_ARB_TIMING_RC */
@@ -1545,8 +1545,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800020ae, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000008, /* MC_EMEM_ARB_CFG */
- 0x80000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000f, /* MC_EMEM_ARB_CFG */
+ 0xc0000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
0x00000003, /* MC_EMEM_ARB_TIMING_RP */
0x0000000d, /* MC_EMEM_ARB_TIMING_RC */
@@ -1665,8 +1665,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800028a5, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000a, /* MC_EMEM_ARB_CFG */
- 0x80000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000014, /* MC_EMEM_ARB_CFG */
+ 0xc0000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
0x00000004, /* MC_EMEM_ARB_TIMING_RP */
0x00000010, /* MC_EMEM_ARB_TIMING_RC */
@@ -1785,8 +1785,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000c, /* MC_EMEM_ARB_CFG */
- 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000016, /* MC_EMEM_ARB_CFG */
+ 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000013, /* MC_EMEM_ARB_TIMING_RC */
@@ -1905,8 +1905,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000c, /* MC_EMEM_ARB_CFG */
- 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000018, /* MC_EMEM_ARB_CFG */
+ 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000013, /* MC_EMEM_ARB_TIMING_RC */
@@ -2025,8 +2025,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000367d, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000d, /* MC_EMEM_ARB_CFG */
- 0x800000a2, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000001b, /* MC_EMEM_ARB_CFG */
+ 0xc00000a2, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000005, /* MC_EMEM_ARB_TIMING_RCD */
0x00000006, /* MC_EMEM_ARB_TIMING_RP */
0x00000016, /* MC_EMEM_ARB_TIMING_RC */
@@ -2148,7 +2148,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -2268,7 +2268,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -2388,7 +2388,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -2508,8 +2508,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000174b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000005, /* MC_EMEM_ARB_CFG */
- 0x80000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000b, /* MC_EMEM_ARB_CFG */
+ 0xc0000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000009, /* MC_EMEM_ARB_TIMING_RC */
@@ -2628,8 +2628,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800018c8, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000006, /* MC_EMEM_ARB_CFG */
- 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0xc0000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000009, /* MC_EMEM_ARB_TIMING_RC */
@@ -2748,8 +2748,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80002d93, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000b, /* MC_EMEM_ARB_CFG */
- 0x80000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000014, /* MC_EMEM_ARB_CFG */
+ 0xc0000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000012, /* MC_EMEM_ARB_TIMING_RC */
@@ -2868,8 +2868,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80002d93, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000b, /* MC_EMEM_ARB_CFG */
- 0x80000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000016, /* MC_EMEM_ARB_CFG */
+ 0xc0000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000012, /* MC_EMEM_ARB_TIMING_RC */
@@ -2988,8 +2988,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2GB1R[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000c, /* MC_EMEM_ARB_CFG */
- 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000018, /* MC_EMEM_ARB_CFG */
+ 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000013, /* MC_EMEM_ARB_TIMING_RC */
@@ -3111,7 +3111,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0x00030003, /* MC_EMEM_ARB_CFG */
0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -3186,14 +3186,14 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00004288, /* 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 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS7 */
0x00000000, /* EMC_DLL_XFORM_QUSE0 */
0x00000000, /* EMC_DLL_XFORM_QUSE1 */
0x00000000, /* EMC_DLL_XFORM_QUSE2 */
@@ -3210,10 +3210,10 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
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 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ3 */
0x000002a0, /* EMC_XM2CMDPADCTRL */
0x0800211c, /* EMC_XM2DQSPADCTRL2 */
0x00000000, /* EMC_XM2DQPADCTRL2 */
@@ -3231,7 +3231,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc0000010, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -3306,14 +3306,14 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00004288, /* 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 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00080000, /* EMC_DLL_XFORM_DQS7 */
0x00000000, /* EMC_DLL_XFORM_QUSE0 */
0x00000000, /* EMC_DLL_XFORM_QUSE1 */
0x00000000, /* EMC_DLL_XFORM_QUSE2 */
@@ -3330,10 +3330,10 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
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 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ0 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ1 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ2 */
+ 0x00080000, /* EMC_DLL_XFORM_DQ3 */
0x000002a0, /* EMC_XM2CMDPADCTRL */
0x0800211c, /* EMC_XM2DQSPADCTRL2 */
0x00000000, /* EMC_XM2DQPADCTRL2 */
@@ -3351,7 +3351,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -3471,7 +3471,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -3591,8 +3591,8 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000174b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000005, /* MC_EMEM_ARB_CFG */
- 0x80000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000b, /* MC_EMEM_ARB_CFG */
+ 0xc0000044, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000009, /* MC_EMEM_ARB_TIMING_RC */
@@ -3711,8 +3711,8 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800018c8, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000006, /* MC_EMEM_ARB_CFG */
- 0x80000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
+ 0xc0000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000009, /* MC_EMEM_ARB_TIMING_RC */
@@ -3831,8 +3831,8 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80002d93, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000b, /* MC_EMEM_ARB_CFG */
- 0x80000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000016, /* MC_EMEM_ARB_CFG */
+ 0xc0000087, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000012, /* MC_EMEM_ARB_TIMING_RC */
@@ -3951,8 +3951,8 @@ static const struct tegra_emc_table cardhu_emc_tables_k4b4g0846b_hyk0[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000308c, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000c, /* MC_EMEM_ARB_CFG */
- 0x80000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000018, /* MC_EMEM_ARB_CFG */
+ 0xc0000090, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000004, /* MC_EMEM_ARB_TIMING_RCD */
0x00000005, /* MC_EMEM_ARB_TIMING_RP */
0x00000013, /* MC_EMEM_ARB_TIMING_RC */
@@ -4194,7 +4194,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800001c2, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0x00030003, /* MC_EMEM_ARB_CFG */
0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -4314,7 +4314,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -4434,7 +4434,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -4554,7 +4554,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -4619,7 +4619,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000004, /* EMC_TCKE */
0x0000000e, /* EMC_TFAW */
0x00000006, /* EMC_TRPAB */
- 0x00000001, /* EMC_TCLKSTABLE */
+ 0x00000004, /* EMC_TCLKSTABLE */
0x00000002, /* EMC_TCLKSTOP */
0x00000455, /* EMC_TREFBW */
0x00000000, /* EMC_QUSE_EXTRA */
@@ -4674,8 +4674,8 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800008ee, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000004, /* MC_EMEM_ARB_CFG */
- 0x80000030, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000008, /* MC_EMEM_ARB_CFG */
+ 0xc0000030, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000008, /* MC_EMEM_ARB_TIMING_RC */
@@ -4794,7 +4794,7 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000dff, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0x0000000d, /* MC_EMEM_ARB_CFG */
0xc000004f, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
0x00000003, /* MC_EMEM_ARB_TIMING_RP */
@@ -4914,8 +4914,8 @@ static const struct tegra_emc_table cardhu_emc_tables_k4p8g304eb[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800010d9, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000008, /* MC_EMEM_ARB_CFG */
- 0x80000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000f, /* MC_EMEM_ARB_CFG */
+ 0xc0000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
0x00000004, /* MC_EMEM_ARB_TIMING_RP */
0x00000010, /* MC_EMEM_ARB_TIMING_RC */
@@ -5037,7 +5037,7 @@ static const struct tegra_emc_table cardhu_emc_tables_edb8132b2ma[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800001c5, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0x00030003, /* MC_EMEM_ARB_CFG */
0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -5157,7 +5157,7 @@ static const struct tegra_emc_table cardhu_emc_tables_edb8132b2ma[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -5277,7 +5277,7 @@ static const struct tegra_emc_table cardhu_emc_tables_edb8132b2ma[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -5397,7 +5397,7 @@ static const struct tegra_emc_table cardhu_emc_tables_edb8132b2ma[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -5517,8 +5517,8 @@ static const struct tegra_emc_table cardhu_emc_tables_edb8132b2ma[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800010d9, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000008, /* MC_EMEM_ARB_CFG */
- 0x80000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000f, /* MC_EMEM_ARB_CFG */
+ 0xc0000060, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
0x00000004, /* MC_EMEM_ARB_TIMING_RP */
0x00000010, /* MC_EMEM_ARB_TIMING_RC */
@@ -5640,7 +5640,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_pm311[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -5760,7 +5760,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_pm311[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -5880,7 +5880,7 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_pm311[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -6000,8 +6000,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_pm311[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800014d4, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000005, /* MC_EMEM_ARB_CFG */
- 0x8000003d, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000a, /* MC_EMEM_ARB_CFG */
+ 0xc000003d, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000008, /* MC_EMEM_ARB_TIMING_RC */
@@ -6120,8 +6120,8 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_pm311[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800028a5, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000a, /* MC_EMEM_ARB_CFG */
- 0x80000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000014, /* MC_EMEM_ARB_CFG */
+ 0xc0000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
0x00000004, /* MC_EMEM_ARB_TIMING_RP */
0x00000010, /* MC_EMEM_ARB_TIMING_RC */
@@ -6151,6 +6151,609 @@ static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_pm311[] = {
},
};
+static const struct tegra_emc_table cardhu_emc_tables_h5tc2g_a2_2g2r[] = {
+ {
+ 0x32, /* Rev 3.2 */
+ 25500, /* SDRAM frequency */
+ {
+ 0x00000001, /* EMC_RC */
+ 0x00000004, /* EMC_RFC */
+ 0x00000000, /* EMC_RAS */
+ 0x00000000, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000000, /* EMC_RD_RCD */
+ 0x00000000, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000007, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x000000c0, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000030, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000005, /* EMC_TXSR */
+ 0x00000005, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000001, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x000000c7, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006288, /* 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 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00030003, /* 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 */
+ 0x00000001, /* 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 */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x74830303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x00001221, /* Mode Register 0 */
+ 0x00100003, /* Mode Register 1 */
+ 0x00200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 51000, /* SDRAM frequency */
+ {
+ 0x00000002, /* EMC_RC */
+ 0x00000008, /* EMC_RFC */
+ 0x00000001, /* EMC_RAS */
+ 0x00000000, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000000, /* EMC_RD_RCD */
+ 0x00000000, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000007, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x00000181, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000060, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000009, /* EMC_TXSR */
+ 0x00000009, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000002, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x0000018e, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006288, /* 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 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00010003, /* 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 */
+ 0x00000001, /* 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 */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0402, /* MC_EMEM_ARB_DA_COVERS */
+ 0x73430303, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x00001221, /* Mode Register 0 */
+ 0x00100003, /* Mode Register 1 */
+ 0x00200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 102000, /* SDRAM frequency */
+ {
+ 0x00000004, /* EMC_RC */
+ 0x00000010, /* EMC_RFC */
+ 0x00000003, /* EMC_RAS */
+ 0x00000001, /* EMC_RP */
+ 0x00000002, /* EMC_R2W */
+ 0x0000000a, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x0000000b, /* EMC_W2P */
+ 0x00000001, /* EMC_RD_RCD */
+ 0x00000001, /* EMC_WR_RCD */
+ 0x00000003, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000005, /* EMC_WDV */
+ 0x00000005, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x00000007, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x00000303, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x000000c0, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x00000002, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000f, /* EMC_RW2PDEN */
+ 0x00000012, /* EMC_TXSR */
+ 0x00000012, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x00000004, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x0000031c, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00006288, /* 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 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0800211c, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f108, /* EMC_XM2COMPPADCTRL */
+ 0x05057404, /* EMC_XM2VTTGENPADCTRL */
+ 0x54000007, /* EMC_XM2VTTGENPADCTRL2 */
+ 0x08000168, /* EMC_XM2QUSEPADCTRL */
+ 0x08000000, /* EMC_XM2DQSPADCTRL3 */
+ 0x00000802, /* EMC_CTT_TERM_CTRL */
+ 0x00000000, /* EMC_ZCAL_INTERVAL */
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT */
+ 0x000c000c, /* 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 */
+ 0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RP */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RC */
+ 0x00000000, /* MC_EMEM_ARB_TIMING_RAS */
+ 0x00000001, /* 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 */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_W2W */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_R2W */
+ 0x00000006, /* MC_EMEM_ARB_TIMING_W2R */
+ 0x06020102, /* MC_EMEM_ARB_DA_TURNS */
+ 0x000a0403, /* MC_EMEM_ARB_DA_COVERS */
+ 0x72830504, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xd8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff00, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x00001221, /* Mode Register 0 */
+ 0x00100003, /* Mode Register 1 */
+ 0x00200008, /* Mode Register 2 */
+ 0x00000001, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 333500, /* SDRAM frequency */
+ {
+ 0x0000000f, /* EMC_RC */
+ 0x00000034, /* EMC_RFC */
+ 0x0000000a, /* EMC_RAS */
+ 0x00000003, /* EMC_RP */
+ 0x00000003, /* EMC_R2W */
+ 0x00000008, /* EMC_W2R */
+ 0x00000002, /* EMC_R2P */
+ 0x00000009, /* EMC_W2P */
+ 0x00000003, /* EMC_RD_RCD */
+ 0x00000003, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000004, /* EMC_WDV */
+ 0x00000006, /* EMC_QUSE */
+ 0x00000004, /* EMC_QRST */
+ 0x0000000a, /* EMC_QSAFE */
+ 0x0000000c, /* EMC_RDV */
+ 0x000009e9, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x0000027a, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000001, /* EMC_PDEX2WR */
+ 0x00000008, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x00000007, /* EMC_AR2PDEN */
+ 0x0000000e, /* EMC_RW2PDEN */
+ 0x00000039, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000004, /* EMC_TCKE */
+ 0x0000000a, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000004, /* EMC_TCLKSTABLE */
+ 0x00000005, /* EMC_TCLKSTOP */
+ 0x00000a2a, /* EMC_TREFBW */
+ 0x00000000, /* EMC_QUSE_EXTRA */
+ 0x00000006, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00007088, /* EMC_FBIO_CFG5 */
+ 0x00260084, /* EMC_CFG_DIG_DLL */
+ 0x00008000, /* EMC_CFG_DIG_DLL_PERIOD */
+ 0x00028000, /* EMC_DLL_XFORM_DQS0 */
+ 0x00028000, /* EMC_DLL_XFORM_DQS1 */
+ 0x00028000, /* EMC_DLL_XFORM_DQS2 */
+ 0x00028000, /* EMC_DLL_XFORM_DQS3 */
+ 0x00028000, /* EMC_DLL_XFORM_DQS4 */
+ 0x00028000, /* EMC_DLL_XFORM_DQS5 */
+ 0x00028000, /* EMC_DLL_XFORM_DQS6 */
+ 0x00028000, /* 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 */
+ 0x0004c000, /* EMC_DLL_XFORM_DQ0 */
+ 0x0004c000, /* EMC_DLL_XFORM_DQ1 */
+ 0x0004c000, /* EMC_DLL_XFORM_DQ2 */
+ 0x0004c000, /* 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 */
+ 0x014b000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800014d4, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x0000000a, /* MC_EMEM_ARB_CFG */
+ 0xc000003d, /* 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 */
+ 0x00000004, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000002, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x00000007, /* 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 */
+ 0x000b0608, /* MC_EMEM_ARB_DA_COVERS */
+ 0x70850f09, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xe8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff88, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000000, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000321, /* Mode Register 0 */
+ 0x00100002, /* Mode Register 1 */
+ 0x00200000, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+ {
+ 0x32, /* Rev 3.2 */
+ 667000, /* SDRAM frequency */
+ {
+ 0x0000001f, /* EMC_RC */
+ 0x00000069, /* EMC_RFC */
+ 0x00000016, /* EMC_RAS */
+ 0x00000008, /* EMC_RP */
+ 0x00000005, /* EMC_R2W */
+ 0x0000000c, /* EMC_W2R */
+ 0x00000003, /* EMC_R2P */
+ 0x00000011, /* EMC_W2P */
+ 0x00000008, /* EMC_RD_RCD */
+ 0x00000008, /* EMC_WR_RCD */
+ 0x00000002, /* EMC_RRD */
+ 0x00000001, /* EMC_REXT */
+ 0x00000000, /* EMC_WEXT */
+ 0x00000007, /* EMC_WDV */
+ 0x0000000b, /* EMC_QUSE */
+ 0x00000009, /* EMC_QRST */
+ 0x0000000c, /* EMC_QSAFE */
+ 0x00000011, /* EMC_RDV */
+ 0x00001412, /* EMC_REFRESH */
+ 0x00000000, /* EMC_BURST_REFRESH_NUM */
+ 0x00000504, /* EMC_PRE_REFRESH_REQ_CNT */
+ 0x00000002, /* EMC_PDEX2WR */
+ 0x0000000e, /* EMC_PDEX2RD */
+ 0x00000001, /* EMC_PCHG2PDEN */
+ 0x00000000, /* EMC_ACT2PDEN */
+ 0x0000000c, /* EMC_AR2PDEN */
+ 0x00000016, /* EMC_RW2PDEN */
+ 0x00000072, /* EMC_TXSR */
+ 0x00000200, /* EMC_TXSRDLL */
+ 0x00000005, /* EMC_TCKE */
+ 0x00000015, /* EMC_TFAW */
+ 0x00000000, /* EMC_TRPAB */
+ 0x00000006, /* EMC_TCLKSTABLE */
+ 0x00000007, /* EMC_TCLKSTOP */
+ 0x00001453, /* EMC_TREFBW */
+ 0x0000000c, /* EMC_QUSE_EXTRA */
+ 0x00000004, /* EMC_FBIO_CFG6 */
+ 0x00000000, /* EMC_ODT_WRITE */
+ 0x00000000, /* EMC_ODT_READ */
+ 0x00005088, /* EMC_FBIO_CFG5 */
+ 0xf00b0191, /* 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 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ0 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ1 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ2 */
+ 0x00000008, /* EMC_DLL_XFORM_DQ3 */
+ 0x000002a0, /* EMC_XM2CMDPADCTRL */
+ 0x0600013d, /* EMC_XM2DQSPADCTRL2 */
+ 0x00000000, /* EMC_XM2DQPADCTRL2 */
+ 0x77fff884, /* EMC_XM2CLKPADCTRL */
+ 0x01f1f508, /* 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 */
+ 0x0116000c, /* EMC_MRS_WAIT_CNT */
+ 0xa0f10000, /* EMC_AUTO_CAL_CONFIG */
+ 0x00000000, /* EMC_CTT */
+ 0x00000000, /* EMC_CTT_DURATION */
+ 0x800028a5, /* EMC_DYN_SELF_REF_CONTROL */
+ 0x00000014, /* MC_EMEM_ARB_CFG */
+ 0xc0000079, /* 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 */
+ 0x0000000a, /* MC_EMEM_ARB_TIMING_FAW */
+ 0x00000001, /* MC_EMEM_ARB_TIMING_RRD */
+ 0x00000003, /* MC_EMEM_ARB_TIMING_RAP2PRE */
+ 0x0000000b, /* 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 */
+ 0x00140c10, /* MC_EMEM_ARB_DA_COVERS */
+ 0x70ea1f11, /* MC_EMEM_ARB_MISC0 */
+ 0x001f0000, /* MC_EMEM_ARB_RING1_THROTTLE */
+ 0xf8000000, /* EMC_FBIO_SPARE */
+ 0xff00ff01, /* EMC_CFG_RSV */
+ },
+ 0x00000040, /* EMC_ZCAL_WAIT_CNT after clock change */
+ 0x001fffff, /* EMC_AUTO_CAL_INTERVAL */
+ 0x00000001, /* EMC_CFG.PERIODIC_QRST */
+ 0x00000b71, /* Mode Register 0 */
+ 0x00100002, /* Mode Register 1 */
+ 0x00200018, /* Mode Register 2 */
+ 0x00000000, /* EMC_CFG.DYN_SELF_REF */
+ },
+};
+
static const u32 pm269_bit_swap_map[32] = {
/* DDR bit # SoC bit # */
[0] = 0x1 << 1,
@@ -6231,6 +6834,9 @@ int cardhu_emc_init(void)
SKU_MEMORY_CARDHU_2GB_1R_HYNIX)
tegra_init_emc(cardhu_emc_tables_h5tc2g_a2_2GB1R,
ARRAY_SIZE(cardhu_emc_tables_h5tc2g_a2_2GB1R));
+ else if (MEMORY_TYPE(board.sku) == SKU_MEMORY_CARDHU_2GB_2R)
+ tegra_init_emc(cardhu_emc_tables_h5tc2g_a2_2g2r,
+ ARRAY_SIZE(cardhu_emc_tables_h5tc2g_a2_2g2r));
break;
}
diff --git a/arch/arm/mach-tegra/board-cardhu-panel.c b/arch/arm/mach-tegra/board-cardhu-panel.c
index 6fa33f919dad..d7101af55712 100644
--- a/arch/arm/mach-tegra/board-cardhu-panel.c
+++ b/arch/arm/mach-tegra/board-cardhu-panel.c
@@ -678,7 +678,11 @@ static struct tegra_fb_data cardhu_fb_data = {
.win = 0,
.xres = 1366,
.yres = 768,
+#ifdef CONFIG_TEGRA_DC_USE_HW_BPP
+ .bits_per_pixel = -1,
+#else
.bits_per_pixel = 32,
+#endif
.flags = TEGRA_FB_FLIP_ON_PROBE,
};
@@ -686,7 +690,11 @@ static struct tegra_fb_data cardhu_hdmi_fb_data = {
.win = 0,
.xres = 640,
.yres = 480,
+#ifdef CONFIG_TEGRA_DC_USE_HW_BPP
+ .bits_per_pixel = -1,
+#else
.bits_per_pixel = 32,
+#endif
.flags = TEGRA_FB_FLIP_ON_PROBE,
};
@@ -873,13 +881,9 @@ static int cardhu_dsi_panel_disable(void)
} 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;
@@ -1213,11 +1217,19 @@ static void cardhu_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_store_default_gov();
+ cpufreq_change_gov(cpufreq_conservative_gov);
+#endif
}
static void cardhu_panel_late_resume(struct early_suspend *h)
{
unsigned i;
+#ifdef CONFIG_TEGRA_CONVSERVATIVE_GOV_ON_EARLYSUPSEND
+ cpufreq_restore_default_gov();
+#endif
for (i = 0; i < num_registered_fb; i++)
fb_blank(registered_fb[i], FB_BLANK_UNBLANK);
}
@@ -1241,6 +1253,9 @@ static void cardhu_panel_preinit(void)
cardhu_disp1_out.n_modes = ARRAY_SIZE(cardhu_panel_modes);
cardhu_disp1_out.enable = cardhu_panel_enable;
cardhu_disp1_out.disable = cardhu_panel_disable;
+ /* Set height and width in mm. */
+ cardhu_disp1_out.height = 125;
+ cardhu_disp1_out.width = 223;
cardhu_disp1_pdata.fb = &cardhu_fb_data;
} else {
@@ -1262,12 +1277,18 @@ static void cardhu_panel_preinit(void)
ARRAY_SIZE(cardhu_dsi_modes_218);
cardhu_dsi_fb_data.xres = 864;
cardhu_dsi_fb_data.yres = 480;
+ /* Set height and width in mm. */
+ cardhu_disp1_out.height = 47;
+ cardhu_disp1_out.width = 84;
} 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;
+ /* Set height and width in mm. */
+ cardhu_disp1_out.height = 95;
+ cardhu_disp1_out.width = 53;
} else if (is_panel_1506) {
cardhu_disp1_out.modes = cardhu_dsi_modes_1506;
cardhu_disp1_out.n_modes =
@@ -1277,9 +1298,13 @@ static void cardhu_panel_preinit(void)
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.panel_send_dc_frames = true;
+ cardhu_dsi.suspend_aggr = DSI_HOST_SUSPEND_LV0;
cardhu_dsi_fb_data.xres = 720;
cardhu_dsi_fb_data.yres = 1280;
+ /* Set height and width in mm. */
+ cardhu_disp1_out.height = 95;
+ cardhu_disp1_out.width = 53;
}
cardhu_disp1_pdata.fb = &cardhu_dsi_fb_data;
@@ -1328,6 +1353,9 @@ int __init cardhu_panel_init(void)
#else
cardhu_disp1_out.depth = 24;
#endif
+ /* Set height and width in mm. */
+ cardhu_disp1_out.height = 135;
+ cardhu_disp1_out.width = 217;
cardhu_fb_data.xres = 1920;
cardhu_fb_data.yres = 1200;
@@ -1376,7 +1404,6 @@ skip_lvds:
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
diff --git a/arch/arm/mach-tegra/board-cardhu-pinmux.c b/arch/arm/mach-tegra/board-cardhu-pinmux.c
index 7b98af0f167c..346dccfd715b 100644
--- a/arch/arm/mach-tegra/board-cardhu-pinmux.c
+++ b/arch/arm/mach-tegra/board-cardhu-pinmux.c
@@ -482,6 +482,9 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_cardhu_a03[] = {
DEFAULT_PINMUX(PEX_L0_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(PEX_L1_CLKREQ_N, RSVD3, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD3, PULL_UP, NORMAL, INPUT),
+
+ /*PCIE dock detect*/
+ DEFAULT_PINMUX(GPIO_PU4, RSVD1, PULL_UP, NORMAL, INPUT),
};
static __initdata struct tegra_pingroup_config cardhu_pinmux_e1291_a04[] = {
@@ -489,6 +492,9 @@ static __initdata struct tegra_pingroup_config cardhu_pinmux_e1291_a04[] = {
DEFAULT_PINMUX(ULPI_DATA6, UARTA, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(SPI2_MOSI, SPI6, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(DAP3_SCLK, RSVD1, NORMAL, NORMAL, OUTPUT),
+
+ /*PCIE dock detect*/
+ DEFAULT_PINMUX(GPIO_PU4, RSVD1, PULL_UP, NORMAL, INPUT),
};
static __initdata struct tegra_pingroup_config cardhu_pinmux_e1198[] = {
@@ -536,6 +542,48 @@ static __initdata struct tegra_pingroup_config unused_pins_lowpower[] = {
DEFAULT_PINMUX(GMI_DQS, NAND, NORMAL, TRISTATE, OUTPUT),
};
+static __initdata struct tegra_pingroup_config unused_pins_lowpower_e1506[] = {
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D5, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D6, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D7, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D9, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D10, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D11, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D12, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D22, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(LCD_DC0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR1, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_CS0_N, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_CS1_N, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_WR_N, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_SCK, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_SDOUT, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_SDIN, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+};
+
static __initdata struct tegra_pingroup_config gmi_pins_269[] = {
/* Continuation of table unused_pins_lowpower only for PM269 */
DEFAULT_PINMUX(GMI_CS0_N, NAND, PULL_UP, NORMAL, OUTPUT),
@@ -686,6 +734,8 @@ int __init cardhu_pinmux_init(void)
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_e1506,
+ ARRAY_SIZE(unused_pins_lowpower_e1506));
}
tegra_pinmux_config_table(unused_pins_lowpower,
@@ -749,6 +799,47 @@ struct gpio_init_pin_info vddio_gmi_pins_pm269_e1506[] = {
PIN_GPIO_LPM("GMI_CS2", TEGRA_GPIO_PK3, 1, 0),
};
+static struct gpio_init_pin_info cardhu_unused_gpio_pins_e1506[] = {
+ PIN_GPIO_LPM("LCD_D0", TEGRA_GPIO_PE0, 0, 0),
+ PIN_GPIO_LPM("LCD_D1", TEGRA_GPIO_PE1, 0, 0),
+ PIN_GPIO_LPM("LCD_D2", TEGRA_GPIO_PE2, 0, 0),
+ PIN_GPIO_LPM("LCD_D3", TEGRA_GPIO_PE3, 0, 0),
+ PIN_GPIO_LPM("LCD_D4", TEGRA_GPIO_PE4, 0, 0),
+ PIN_GPIO_LPM("LCD_D5", TEGRA_GPIO_PE5, 0, 0),
+ PIN_GPIO_LPM("LCD_D6", TEGRA_GPIO_PE6, 0, 0),
+ PIN_GPIO_LPM("LCD_D7", TEGRA_GPIO_PE7, 0, 0),
+ PIN_GPIO_LPM("LCD_D8", TEGRA_GPIO_PF0, 0, 0),
+ PIN_GPIO_LPM("LCD_D9", TEGRA_GPIO_PF1, 0, 0),
+ PIN_GPIO_LPM("LCD_D10", TEGRA_GPIO_PF2, 0, 0),
+ PIN_GPIO_LPM("LCD_D11", TEGRA_GPIO_PF3, 0, 0),
+ PIN_GPIO_LPM("LCD_D12", TEGRA_GPIO_PF4, 0, 0),
+ PIN_GPIO_LPM("LCD_D13", TEGRA_GPIO_PF5, 0, 0),
+ PIN_GPIO_LPM("LCD_D14", TEGRA_GPIO_PF6, 0, 0),
+ PIN_GPIO_LPM("LCD_D15", TEGRA_GPIO_PF7, 0, 0),
+ PIN_GPIO_LPM("LCD_D16", TEGRA_GPIO_PM0, 0, 0),
+ PIN_GPIO_LPM("LCD_D17", TEGRA_GPIO_PM1, 0, 0),
+ PIN_GPIO_LPM("LCD_D18", TEGRA_GPIO_PM2, 0, 0),
+ PIN_GPIO_LPM("LCD_D19", TEGRA_GPIO_PM3, 0, 0),
+ PIN_GPIO_LPM("LCD_D20", TEGRA_GPIO_PM4, 0, 0),
+ PIN_GPIO_LPM("LCD_D21", TEGRA_GPIO_PM5, 0, 0),
+ PIN_GPIO_LPM("LCD_D22", TEGRA_GPIO_PM6, 0, 0),
+ PIN_GPIO_LPM("LCD_D23", TEGRA_GPIO_PM7, 0, 0),
+
+ PIN_GPIO_LPM("LCD_DC0", TEGRA_GPIO_PN6, 0, 0),
+ PIN_GPIO_LPM("LCD_PWR0", TEGRA_GPIO_PB2, 0, 0),
+ PIN_GPIO_LPM("LCD_PWR1", TEGRA_GPIO_PC1, 0, 0),
+ PIN_GPIO_LPM("LCD_PWR2", TEGRA_GPIO_PC6, 0, 0),
+ PIN_GPIO_LPM("LCD_CS0_N", TEGRA_GPIO_PN4, 0, 0),
+ PIN_GPIO_LPM("LCD_CS1_N", TEGRA_GPIO_PW0, 0, 0),
+ PIN_GPIO_LPM("LCD_PCLK", TEGRA_GPIO_PB3, 0, 0),
+ PIN_GPIO_LPM("LCD_WR_N", TEGRA_GPIO_PZ3, 0, 0),
+ PIN_GPIO_LPM("LCD_HSYNC", TEGRA_GPIO_PJ3, 0, 0),
+ PIN_GPIO_LPM("LCD_VSYNC", TEGRA_GPIO_PJ4, 0, 0),
+ PIN_GPIO_LPM("LCD_SCK", TEGRA_GPIO_PZ4, 0, 0),
+ PIN_GPIO_LPM("LCD_SDOUT", TEGRA_GPIO_PN5, 0, 0),
+ PIN_GPIO_LPM("LCD_SDIN", TEGRA_GPIO_PZ2, 0, 0),
+};
+
static void set_unused_pin_gpio(struct gpio_init_pin_info *lpm_pin_info,
int list_count)
{
@@ -811,6 +902,8 @@ int __init cardhu_pins_state_init(void)
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));
+ set_unused_pin_gpio(cardhu_unused_gpio_pins_e1506,
+ ARRAY_SIZE(cardhu_unused_gpio_pins_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-power.c b/arch/arm/mach-tegra/board-cardhu-power.c
index ace103f5ba6b..677b38347514 100644
--- a/arch/arm/mach-tegra/board-cardhu-power.c
+++ b/arch/arm/mach-tegra/board-cardhu-power.c
@@ -538,7 +538,10 @@ static struct regulator_consumer_supply fixed_reg_en_3v3_sys_supply[] = {
REGULATOR_SUPPLY("hvdd_pex_pmu", NULL),
REGULATOR_SUPPLY("avdd_hdmi", NULL),
REGULATOR_SUPPLY("vpp_fuse", NULL),
- REGULATOR_SUPPLY("avdd_usb", NULL),
+ REGULATOR_SUPPLY("avdd_usb", "tegra-udc.0"),
+ REGULATOR_SUPPLY("avdd_usb", "tegra-ehci.0"),
+ REGULATOR_SUPPLY("avdd_usb", "tegra-ehci.1"),
+ REGULATOR_SUPPLY("avdd_usb", "tegra-ehci.2"),
REGULATOR_SUPPLY("vdd_ddr_rx", NULL),
REGULATOR_SUPPLY("vcore_nand", NULL),
REGULATOR_SUPPLY("hvdd_sata", NULL),
@@ -1131,15 +1134,25 @@ static struct tegra_suspend_platform_data cardhu_suspend_data = {
.cpu_lp2_min_residency = 2000,
.board_suspend = cardhu_board_suspend,
.board_resume = cardhu_board_resume,
+#ifdef CONFIG_TEGRA_LP1_950
+ .lp1_lowvolt_support = false,
+ .i2c_base_addr = 0,
+ .pmuslave_addr = 0,
+ .core_reg_addr = 0,
+ .lp1_core_volt_low = 0,
+ .lp1_core_volt_high = 0,
+#endif
};
int __init cardhu_suspend_init(void)
{
struct board_info board_info;
struct board_info pmu_board_info;
+ struct board_info display_board_info;
tegra_get_board_info(&board_info);
tegra_get_pmu_board_info(&pmu_board_info);
+ tegra_get_display_board_info(&display_board_info);
/* For PMU Fab A03, A04 and A05 make core_pwr_req to high */
if ((pmu_board_info.fab == BOARD_FAB_A03) ||
@@ -1158,25 +1171,43 @@ int __init cardhu_suspend_init(void)
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 */
+ /* post E1291-A02 revisions 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 */
+ /* post E1198-A01 revisions VBUS wake supported */
tegra_disable_wake_source(TEGRA_WAKE_USB1_VBUS);
break;
case BOARD_PM269:
+#ifdef CONFIG_TEGRA_LP1_950
+ /* AP37 board supports the LP1_950mV feature */
+ if (is_display_board_dsi(display_board_info.board_id)) {
+ cardhu_suspend_data.lp1_lowvolt_support = true;
+ cardhu_suspend_data.i2c_base_addr = TEGRA_I2C5_BASE;
+ cardhu_suspend_data.pmuslave_addr = 0xC0;
+ cardhu_suspend_data.core_reg_addr = 0x03;
+ cardhu_suspend_data.lp1_core_volt_low = 0x2D;
+ cardhu_suspend_data.lp1_core_volt_high = 0x50;
+ }
+#endif
+ if (is_display_board_dsi(display_board_info.board_id))
+ cardhu_suspend_data.cpu_wake_freq = CPU_WAKE_FREQ_LOW;
case BOARD_PM305:
case BOARD_PM311:
break;
- case BOARD_E1187:
- case BOARD_E1186:
case BOARD_E1256:
case BOARD_E1257:
cardhu_suspend_data.cpu_timer = 5000;
cardhu_suspend_data.cpu_off_timer = 5000;
break;
+ case BOARD_E1187:
+ case BOARD_E1186:
+ /* VBUS repeated wakeup seen on older E1186 boards */
+ tegra_disable_wake_source(TEGRA_WAKE_USB1_VBUS);
+ cardhu_suspend_data.cpu_timer = 5000;
+ cardhu_suspend_data.cpu_off_timer = 5000;
+ break;
default:
break;
}
diff --git a/arch/arm/mach-tegra/board-cardhu-sdhci.c b/arch/arm/mach-tegra/board-cardhu-sdhci.c
index d8be9fe6747f..df7177fb34a7 100644
--- a/arch/arm/mach-tegra/board-cardhu-sdhci.c
+++ b/arch/arm/mach-tegra/board-cardhu-sdhci.c
@@ -28,6 +28,7 @@
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/sdhci.h>
+#include <mach/io_dpd.h>
#include "gpio-names.h"
#include "board.h"
@@ -251,11 +252,31 @@ static int cardhu_wifi_set_carddetect(int val)
static int cardhu_wifi_power(int on)
{
+ struct tegra_io_dpd *sd_dpd;
+
pr_debug("%s: %d\n", __func__, on);
+
+ /*
+ * FIXME : we need to revisit IO DPD code
+ * on how should multiple pins under DPD get controlled
+ *
+ * cardhu GPIO WLAN enable is part of SDMMC3 pin group
+ */
+ sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device2.dev);
+ if (sd_dpd) {
+ mutex_lock(&sd_dpd->delay_lock);
+ tegra_io_dpd_disable(sd_dpd);
+ mutex_unlock(&sd_dpd->delay_lock);
+ }
gpio_set_value(CARDHU_WLAN_PWR, on);
mdelay(100);
gpio_set_value(CARDHU_WLAN_RST, on);
mdelay(200);
+ if (sd_dpd) {
+ mutex_lock(&sd_dpd->delay_lock);
+ tegra_io_dpd_enable(sd_dpd);
+ mutex_unlock(&sd_dpd->delay_lock);
+ }
return 0;
}
diff --git a/arch/arm/mach-tegra/board-cardhu-sensors.c b/arch/arm/mach-tegra/board-cardhu-sensors.c
index bb6a2ae5774d..7e9774f290eb 100644
--- a/arch/arm/mach-tegra/board-cardhu-sensors.c
+++ b/arch/arm/mach-tegra/board-cardhu-sensors.c
@@ -340,7 +340,7 @@ static int cardhu_right_ov5650_power_off(void)
gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 0);
/* Boards E1198 and E1291 are of Cardhu personality
- * and donot have TCA6416 exp for camera */
+ * and do not have TCA6416 for camera */
if ((board_info.board_id == BOARD_E1198) ||
(board_info.board_id == BOARD_E1291)) {
gpio_direction_output(CAM1_POWER_DWN_GPIO, 1);
@@ -387,16 +387,21 @@ static int cardhu_ov2710_power_on(void)
/* CSI-B and front sensor are muxed on cardhu */
gpio_direction_output(CAMERA_CSI_MUX_SEL_GPIO, 1);
+ /* 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);
+
/* Boards E1198 and E1291 are of Cardhu personality
- * and donot have TCA6416 exp for camera */
+ * and do not have TCA6416 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))) {
@@ -406,19 +411,17 @@ static int cardhu_ov2710_power_on(void)
}
}
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;
- }
+ mdelay(5);
+
+ 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);
+
}
- regulator_enable(cardhu_1v8_cam3);
- mdelay(5);
+
+ mdelay(20);
return 0;
@@ -447,12 +450,12 @@ static int cardhu_ov2710_power_off(void)
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_vdd_cam3)
+ regulator_disable(cardhu_vdd_cam3);
}
if (cardhu_1v8_cam3)
regulator_disable(cardhu_1v8_cam3);
- if (cardhu_vdd_cam3)
- regulator_disable(cardhu_vdd_cam3);
return 0;
}
diff --git a/arch/arm/mach-tegra/board-cardhu.c b/arch/arm/mach-tegra/board-cardhu.c
index b5fa3f316698..e14e6b25d644 100644
--- a/arch/arm/mach-tegra/board-cardhu.c
+++ b/arch/arm/mach-tegra/board-cardhu.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/board-cardhu.c
*
* Copyright (c) 2011-2012, NVIDIA Corporation. All rights reserved.
+ * 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
@@ -44,12 +45,14 @@
#include <sound/wm8903.h>
#include <sound/max98095.h>
#include <media/tegra_dtv.h>
+#include <media/tegra_camera.h>
#include <mach/clk.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
#include <mach/pinmux.h>
#include <mach/iomap.h>
+#include <mach/io_dpd.h>
#include <mach/io.h>
#include <mach/i2s.h>
#include <mach/tegra_asoc_pdata.h>
@@ -491,6 +494,16 @@ static void __init uart_debug_init(void)
debug_port_id = 1;
}
+#ifdef CONFIG_TEGRA_IRDA
+ if ((board_info.board_id == BOARD_E1186) ||
+ (board_info.board_id == BOARD_E1198)) {
+ if (debug_port_id == 1) {
+ cardhu_irda_pdata.is_irda = false;
+ pr_err("UARTB is not available for IrDA\n");
+ }
+ }
+#endif
+
switch (debug_port_id) {
case 0:
/* UARTA is the debug port. */
@@ -552,6 +565,9 @@ static void __init cardhu_uart_init(void)
{
struct clk *c;
int i;
+ struct board_info board_info;
+
+ tegra_get_board_info(&board_info);
for (i = 0; i < ARRAY_SIZE(uart_parent_clk); ++i) {
c = tegra_get_clock_by_name(uart_parent_clk[i].name);
@@ -597,15 +613,44 @@ static void __init cardhu_uart_init(void)
}
}
+#ifdef CONFIG_TEGRA_IRDA
+ if (((board_info.board_id == BOARD_E1186) ||
+ (board_info.board_id == BOARD_E1198)) &&
+ cardhu_irda_pdata.is_irda) {
+ cardhu_irda_pdata.parent_clk_list = uart_parent_clk;
+ cardhu_irda_pdata.parent_clk_count =
+ ARRAY_SIZE(uart_parent_clk);
+
+ tegra_uartb_device.dev.platform_data = &cardhu_irda_pdata;
+ }
+#endif
+
platform_add_devices(cardhu_uart_devices,
ARRAY_SIZE(cardhu_uart_devices));
}
+static struct tegra_camera_platform_data tegra_camera_pdata = {
+ .limit_3d_emc_clk = false,
+};
+
static struct platform_device tegra_camera = {
.name = "tegra_camera",
+ .dev = {
+ .platform_data = &tegra_camera_pdata,
+ },
.id = -1,
};
+static void tegra_camera_init(void)
+{
+ /* For AP37 platform, limit 3d and emc freq when camera is ON */
+ if (TEGRA_REVISION_A03 == tegra_get_revision() &&
+ 0xA0 == tegra_sku_id())
+ tegra_camera_pdata.limit_3d_emc_clk = true;
+ else
+ tegra_camera_pdata.limit_3d_emc_clk = false;
+}
+
static struct platform_device *cardhu_spi_devices[] __initdata = {
&tegra_spi_device4,
};
@@ -698,12 +743,25 @@ static struct platform_device tegra_rtc_device = {
.num_resources = ARRAY_SIZE(tegra_rtc_resources),
};
-static struct tegra_wm8903_platform_data cardhu_audio_wm8903_pdata = {
+static struct tegra_asoc_platform_data cardhu_audio_wm8903_pdata = {
.gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
.gpio_hp_det = TEGRA_GPIO_HP_DET,
.gpio_hp_mute = -1,
.gpio_int_mic_en = -1,
.gpio_ext_mic_en = -1,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ },
};
static struct tegra_asoc_platform_data cardhu_audio_max98095_pdata = {
@@ -712,6 +770,19 @@ static struct tegra_asoc_platform_data cardhu_audio_max98095_pdata = {
.gpio_hp_mute = -1,
.gpio_int_mic_en = -1,
.gpio_ext_mic_en = -1,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ },
};
static struct platform_device cardhu_audio_wm8903_device = {
@@ -737,14 +808,17 @@ static struct tegra_asoc_platform_data cardhu_audio_aic326x_pdata = {
.gpio_int_mic_en = -1,
.gpio_ext_mic_en = -1,
/*defaults for Verbier-Cardhu board with TI AIC326X codec*/
- .audio_port_id = {
- [HIFI_CODEC] = 0,
- [BASEBAND] = -1,
- [BT_SCO] = 3,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ .sample_size = 16,
},
- .baseband_param = {
- .rate = -1,
- .channels = -1,
+ .i2s_param[BT_SCO] = {
+ .sample_size = 16,
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
},
};
@@ -1008,13 +1082,6 @@ static struct tegra_usb_platform_data tegra_ehci2_hsic_xmm_pdata = {
.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
@@ -1035,10 +1102,6 @@ void hsic_platform_open(void)
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 */
@@ -1098,13 +1161,6 @@ static struct tegra_usb_platform_data tegra_ehci2_hsic_pdata = {
.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,
};
@@ -1384,8 +1440,10 @@ static void __init tegra_cardhu_init(void)
cardhu_edp_init();
#endif
cardhu_uart_init();
+ tegra_camera_init();
platform_add_devices(cardhu_devices, ARRAY_SIZE(cardhu_devices));
tegra_ram_console_debug_init();
+ tegra_io_dpd_init();
cardhu_sdhci_init();
cardhu_regulator_init();
cardhu_dtv_init();
@@ -1422,6 +1480,11 @@ static void __init tegra_cardhu_reserve(void)
tegra_ram_console_debug_reserve(SZ_1M);
}
+static const char *cardhu_dt_board_compat[] = {
+ "nvidia,cardhu",
+ NULL
+};
+
MACHINE_START(CARDHU, "cardhu")
.boot_params = 0x80000100,
.map_io = tegra_map_common_io,
@@ -1430,4 +1493,5 @@ MACHINE_START(CARDHU, "cardhu")
.init_irq = tegra_init_irq,
.timer = &tegra_timer,
.init_machine = tegra_cardhu_init,
+ .dt_compat = cardhu_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-tegra/board-cardhu.h b/arch/arm/mach-tegra/board-cardhu.h
index a8be32ec9cdd..3dd3d23d9414 100644
--- a/arch/arm/mach-tegra/board-cardhu.h
+++ b/arch/arm/mach-tegra/board-cardhu.h
@@ -221,6 +221,8 @@ int cardhu_pm298_regulator_init(void);
int cardhu_pm299_gpio_switch_regulator_init(void);
int cardhu_pm299_regulator_init(void);
+extern struct tegra_uart_platform_data cardhu_irda_pdata;
+
#define MPU_TYPE_MPU3050 1
#define MPU_TYPE_MPU6050 2
#define MPU_GYRO_TYPE MPU_TYPE_MPU3050
@@ -229,7 +231,7 @@ int cardhu_pm299_regulator_init(void);
#define MPU_GYRO_BUS_NUM 2
#define MPU_GYRO_ORIENTATION { 0, -1, 0, -1, 0, 0, 0, 0, -1 }
#define MPU_ACCEL_NAME "kxtf9"
-#define MPU_ACCEL_IRQ_GPIO TEGRA_GPIO_PL1
+#define MPU_ACCEL_IRQ_GPIO 0 /* DISABLE ACCELIRQ: TEGRA_GPIO_PL1 */
#define MPU_ACCEL_ADDR 0x0F
#define MPU_ACCEL_BUS_NUM 2
#define MPU_ACCEL_ORIENTATION { 0, -1, 0, -1, 0, 0, 0, 0, -1 }
diff --git a/arch/arm/mach-tegra/board-e1853-panel.c b/arch/arm/mach-tegra/board-e1853-panel.c
new file mode 100644
index 000000000000..a4d6bc66f4e7
--- /dev/null
+++ b/arch/arm/mach-tegra/board-e1853-panel.c
@@ -0,0 +1,202 @@
+/*
+ * arch/arm/mach-tegra/board-e1853-panel.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/resource.h>
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+#include <linux/nvhost.h>
+#include <linux/nvmap.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+#include <mach/dc.h>
+#include <mach/fb.h>
+
+#include "board.h"
+#include "devices.h"
+#include "tegra3_host1x_devices.h"
+#include "gpio-names.h"
+
+#define E1853_HDMI_HPD TEGRA_GPIO_PB2
+
+static int e1853_panel_enable(void)
+{
+ return 0;
+}
+
+static int e1853_panel_disable(void)
+{
+ return 0;
+}
+
+static struct tegra_dc_mode e1853_panel_modes[] = {
+ {
+ /* 800x480@60 */
+ .pclk = 32460000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 64,
+ .v_sync_width = 3,
+ .h_back_porch = 128,
+ .v_back_porch = 22,
+ .h_front_porch = 64,
+ .v_front_porch = 20,
+ .h_active = 800,
+ .v_active = 480,
+ },
+};
+
+static struct tegra_fb_data e1853_fb_data = {
+ .win = 0,
+ .xres = 800,
+ .yres = 480,
+ .bits_per_pixel = 32,
+};
+
+static struct tegra_dc_out e1853_disp1_out = {
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .type = TEGRA_DC_OUT_RGB,
+ .modes = e1853_panel_modes,
+ .n_modes = ARRAY_SIZE(e1853_panel_modes),
+ .enable = e1853_panel_enable,
+ .disable = e1853_panel_disable,
+};
+
+static struct tegra_dc_platform_data e1853_disp1_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &e1853_disp1_out,
+ .emc_clk_rate = 300000000,
+ .fb = &e1853_fb_data,
+};
+
+static int e1853_hdmi_enable(void)
+{
+ return 0;
+}
+
+static int e1853_hdmi_disable(void)
+{
+ return 0;
+}
+
+static struct tegra_fb_data e1853_hdmi_fb_data = {
+ .win = 0,
+ .xres = 800,
+ .yres = 480,
+ .bits_per_pixel = 32,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_dc_out e1853_hdmi_out = {
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .parent_clk = "pll_d2_out0",
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_LOW |
+ TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND,
+ .max_pixclock = KHZ2PICOS(148500),
+ /* XXX: Check the GPIO */
+ .hotplug_gpio = E1853_HDMI_HPD,
+ .enable = e1853_hdmi_enable,
+ .disable = e1853_hdmi_disable,
+ /* XXX: Check the I2C instance */
+ .dcc_bus = 3,
+};
+
+static struct tegra_dc_platform_data e1853_hdmi_pdata = {
+ .flags = 0,
+ .default_out = &e1853_hdmi_out,
+ .emc_clk_rate = 300000000,
+ .fb = &e1853_hdmi_fb_data,
+};
+
+static struct nvmap_platform_carveout e1853_carveouts[] = {
+ [0] = {
+ .name = "iram",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_IRAM,
+ .base = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE,
+ .size = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE,
+ .buddy_size = 0, /* no buddy allocation for IRAM */
+ },
+ [1] = {
+ .name = "generic-0",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC,
+ .base = 0, /* Filled in by e1853_panel_init() */
+ .size = 0, /* Filled in by e1853_panel_init() */
+ .buddy_size = SZ_32K,
+ },
+};
+
+static struct nvmap_platform_data e1853_nvmap_data = {
+ .carveouts = e1853_carveouts,
+ .nr_carveouts = ARRAY_SIZE(e1853_carveouts),
+};
+
+static struct platform_device *e1853_gfx_devices[] __initdata = {
+ &tegra_nvmap_device,
+};
+
+int __init e1853_panel_init(void)
+{
+ int err;
+ struct resource *res;
+
+ e1853_carveouts[1].base = tegra_carveout_start;
+ e1853_carveouts[1].size = tegra_carveout_size;
+ tegra_nvmap_device.dev.platform_data = &e1853_nvmap_data;
+ tegra_disp1_device.dev.platform_data = &e1853_disp1_pdata;
+ tegra_disp2_device.dev.platform_data = &e1853_hdmi_pdata;
+
+#ifdef CONFIG_TEGRA_GRHOST
+ err = tegra3_register_host1x_devices();
+ if (err)
+ return err;
+#endif
+
+ err = platform_add_devices(e1853_gfx_devices,
+ ARRAY_SIZE(e1853_gfx_devices));
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ res = nvhost_get_resource_byname(&tegra_disp1_device,
+ IORESOURCE_MEM, "fbmem");
+ if (res) {
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+ }
+
+ if (!err)
+ err = nvhost_device_register(&tegra_disp1_device);
+
+ res = nvhost_get_resource_byname(&tegra_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ if (res) {
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
+ }
+
+ if (!err)
+ err = nvhost_device_register(&tegra_disp2_device);
+#endif
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP)
+ if (!err)
+ err = nvhost_device_register(&nvavp_device);
+#endif
+ return err;
+}
diff --git a/arch/arm/mach-tegra/board-e1853-pinmux.c b/arch/arm/mach-tegra/board-e1853-pinmux.c
new file mode 100644
index 000000000000..9e81b7035aba
--- /dev/null
+++ b/arch/arm/mach-tegra/board-e1853-pinmux.c
@@ -0,0 +1,502 @@
+/*
+ * arch/arm/mach-tegra/board-e1853-pinmux.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/kernel.h>
+#include <linux/init.h>
+#include <mach/pinmux.h>
+#include <linux/gpio.h>
+#include "board.h"
+#include "board-e1853.h"
+#include "gpio-names.h"
+
+#define DEFAULT_DRIVE(_name) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_DISABLE, \
+ .schmitt = TEGRA_SCHMITT_ENABLE, \
+ .drive = TEGRA_DRIVE_DIV_1, \
+ .pull_down = TEGRA_PULL_31, \
+ .pull_up = TEGRA_PULL_31, \
+ .slew_rising = TEGRA_SLEW_SLOWEST, \
+ .slew_falling = TEGRA_SLEW_SLOWEST, \
+ }
+/* Setting the drive strength of pins
+ * hsm: Enable High speed mode (ENABLE/DISABLE)
+ * Schimit: Enable/disable schimit (ENABLE/DISABLE)
+ * drive: low power mode (DIV_1, DIV_2, DIV_4, DIV_8)
+ * pulldn_drive - drive down (falling edge) - Driver Output Pull-Down drive
+ * strength code. Value from 0 to 31.
+ * pullup_drive - drive up (rising edge) - Driver Output Pull-Up drive
+ * strength code. Value from 0 to 31.
+ * pulldn_slew - Driver Output Pull-Up slew control code - 2bit code
+ * code 11 is least slewing of signal. code 00 is highest
+ * slewing of the signal.
+ * Value - FASTEST, FAST, SLOW, SLOWEST
+ * pullup_slew - Driver Output Pull-Down slew control code -
+ * code 11 is least slewing of signal. code 00 is highest
+ * slewing of the signal.
+ * Value - FASTEST, FAST, SLOW, SLOWEST
+ */
+#define SET_DRIVE(_name, _hsm, _schmitt, _drive, _pulldn_drive, _pullup_drive, _pulldn_slew, _pullup_slew) \
+ { \
+ .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
+ .hsm = TEGRA_HSM_##_hsm, \
+ .schmitt = TEGRA_SCHMITT_##_schmitt, \
+ .drive = TEGRA_DRIVE_##_drive, \
+ .pull_down = TEGRA_PULL_##_pulldn_drive, \
+ .pull_up = TEGRA_PULL_##_pullup_drive, \
+ .slew_rising = TEGRA_SLEW_##_pulldn_slew, \
+ .slew_falling = TEGRA_SLEW_##_pullup_slew, \
+ }
+
+/* !!!FIXME!!!! Update drive strength with characterized value */
+static __initdata struct tegra_drive_pingroup_config e1853_drive_pinmux[] = {
+ /* 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, 12, 30, FASTEST, FASTEST),
+
+ /* DDC I2C */
+ SET_DRIVE(DDC, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* PWR_I2C */
+ SET_DRIVE(AO1, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* SDMMC4 */
+ SET_DRIVE(GME, DISABLE, ENABLE, DIV_1, 22, 18, SLOWEST, SLOWEST),
+ 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),
+
+ /* SDMMC 3 */
+ SET_DRIVE(SDIO3, DISABLE, DISABLE, DIV_1, 46, 42, FAST, FAST),
+};
+
+#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \
+ { \
+ .pingroup = TEGRA_PINGROUP_##_pingroup, \
+ .func = TEGRA_MUX_##_mux, \
+ .pupd = TEGRA_PUPD_##_pupd, \
+ .tristate = TEGRA_TRI_##_tri, \
+ .io = TEGRA_PIN_##_io, \
+ .lock = TEGRA_PIN_LOCK_DEFAULT, \
+ .od = TEGRA_PIN_OD_DEFAULT, \
+ .ioreset = TEGRA_PIN_IO_RESET_DEFAULT, \
+ }
+
+#define I2C_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, \
+ }
+
+#define VI_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 e1853_pinmux_common[] = {
+
+ /* CLK-EXTCLK1 */
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CLK3_OUT, EXTPERIPH3, NORMAL, NORMAL, OUTPUT),
+
+ /* SDMMC1 pinmux */
+ DEFAULT_PINMUX(SDMMC1_CLK, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_CMD, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT3, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT2, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT1, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT0, SDMMC1, PULL_UP, NORMAL, INPUT),
+
+ /* SDMMC2 pinmux */
+ DEFAULT_PINMUX(KB_ROW10, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW11, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW12, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW13, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW14, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW15, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW6, SDMMC2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW7, SDMMC2, PULL_UP, NORMAL, INPUT),
+ 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),
+
+ /* I2C1 pinmux */
+ I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(GEN1_I2C_SDA, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* I2C2 pinmux */
+ I2C_PINMUX(GEN2_I2C_SCL, I2C2, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(GEN2_I2C_SDA, I2C2, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* I2C3 pinmux */
+ I2C_PINMUX(CAM_I2C_SCL, I2C3, PULL_UP, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(CAM_I2C_SDA, I2C3, PULL_UP, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* I2C4 pinmux */
+ I2C_PINMUX(DDC_SCL, I2C4, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(DDC_SDA, I2C4, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* PowerI2C pinmux */
+ I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* UART1 pinmux */
+ DEFAULT_PINMUX(GPIO_PU0, UARTA, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU1, UARTA, NORMAL, NORMAL, INPUT),
+
+ /* UART2 pinmux */
+ DEFAULT_PINMUX(UART2_CTS_N, UARTB, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_RTS_N, UARTB, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_TXD, IRDA, PULL_UP, NORMAL, OUTPUT),
+
+ /* UART3 pinmux */
+ DEFAULT_PINMUX(UART3_CTS_N, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_RTS_N, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_TXD, UARTC, PULL_UP, NORMAL, OUTPUT),
+
+ /* UART4 pinmux */
+ DEFAULT_PINMUX(ULPI_CLK, UARTD, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_DIR, UARTD, NORMAL, NORMAL, INPUT),
+
+ /* SPI2 pinmux */
+ DEFAULT_PINMUX(ULPI_DATA4, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA5, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA6, SPI2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA7, SPI2, NORMAL, NORMAL, INPUT),
+
+ /* SPI3 pinmux */
+ DEFAULT_PINMUX(ULPI_DATA0, SPI3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA1, SPI3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA2, SPI3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA3, SPI3, NORMAL, NORMAL, INPUT),
+
+ /* SPI5 pinmux */
+ DEFAULT_PINMUX(LCD_SCK, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_CS0_N, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDIN, SPI5, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_SDOUT, SPI5, NORMAL, NORMAL, INPUT),
+
+ /* DAP1 */
+ DEFAULT_PINMUX(DAP1_FS, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DIN, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DOUT, I2S0, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP1_SCLK, I2S0, NORMAL, NORMAL, INPUT),
+
+ /* DAP2 */
+ DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
+
+ /* I2S1 */
+ DEFAULT_PINMUX(DAP2_DIN, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DOUT, I2S1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP2_FS, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_SCLK, I2S1, NORMAL, NORMAL, INPUT),
+
+ /* I2S3 */
+ DEFAULT_PINMUX(DAP4_DIN, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DOUT, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_FS, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_SCLK, I2S3, NORMAL, NORMAL, INPUT),
+
+ /* NOR pinmux */
+ DEFAULT_PINMUX(SDMMC4_DAT0, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT1, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT2, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT3, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT4, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT5, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT6, GMI, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(GMI_A16, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A17, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A18, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A19, GMI, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(GMI_AD0, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD1, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD2, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD3, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD4, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD5, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD6, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD7, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD8, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD9, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD10, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD11, GMI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD12, GMI, NORMAL, NORMAL, INPUT),
+ 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_CS0_N, GMI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_OE_N, GMI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_RST_N, GMI, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_WAIT, GMI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_WP_N, GMI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_WR_N, GMI, NORMAL, NORMAL, OUTPUT),
+
+ /* DISPLAY pinmux */
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D6, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D7, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D11, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D22, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+
+ /* PCIE */
+ DEFAULT_PINMUX(PEX_L0_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L1_RST_N, PCIE, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(PEX_L1_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L0_RST_N, PCIE, PULL_UP, NORMAL, OUTPUT),
+
+ 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, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D5, VI, NORMAL, NORMAL, INPUT, 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, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_HSYNC, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_VSYNC, VI, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+
+ /* pin config for gpios */
+ DEFAULT_PINMUX(PEX_L2_CLKREQ_N, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L1_PRSNT_N, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_CS1_N, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DC0, RSVD1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DC1, RSVD1, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(VI_D0, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_NXT, RSVD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_STP, RSVD, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(CRT_VSYNC, RSVD1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(CRT_HSYNC, RSVD1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR1, RSVD1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR2, RSVD, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L0_PRSNT_N, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV2, RSVD1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT7, RSVD, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, PULL_DOWN, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CLK3_REQ, RSVD1, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV1, RSVD, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_M1, RSVD1, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_MCLK, VI, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_WR_N, RSVD, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_PRSNT_N, RSVD2, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_RST_N, RSVD2, PULL_DOWN, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_WAKE_N, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(HDMI_INT, RSVD, PULL_DOWN, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW1, RSVD2, PULL_DOWN, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW2, RSVD2, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW3, RSVD2, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW4, RSVD3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D10, RSVD1, PULL_DOWN, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(VI_D11, RSVD1, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, PULL_DOWN, NORMAL, INPUT),
+
+ /*
+ * unused pins: tristate them all.
+ */
+ DEFAULT_PINMUX(SPI2_CS0_N, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_SCK, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_MOSI, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_MISO, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU2, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU3, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU4, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU5, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU6, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CLK1_REQ, RSVD2, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_CS1_N, SPI2, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPDIF_OUT, SAFE, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_CS0_N, SPI1, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_MISO, SPI1, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_MOSI, SPI1, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_SCK, SPI1, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CAM_MCLK, POPSDMMC4, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PCC1, POPSDMMC4, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PCC2, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB0, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB3, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB4, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB5, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB6, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB7, POPSDMMC4, PULL_UP, TRISTATE, OUTPUT),
+
+};
+
+int __init e1853_pinmux_init(void)
+{
+ tegra_pinmux_config_table(e1853_pinmux_common,
+ ARRAY_SIZE(e1853_pinmux_common));
+ tegra_drive_pinmux_config_table(e1853_drive_pinmux,
+ ARRAY_SIZE(e1853_drive_pinmux));
+ return 0;
+}
+
+static struct gpio e1853_sku8_gpios[] = {
+ {TEGRA_GPIO_PV0, GPIOF_IN, "v0"},
+ {TEGRA_GPIO_PV1, GPIOF_IN, "v1"},
+ {TEGRA_GPIO_PY2, GPIOF_OUT_INIT_HIGH, "y2"},
+ {TEGRA_GPIO_PY3, GPIOF_IN, "y3"},
+ {TEGRA_GPIO_PV6, GPIOF_IN, "v6"},
+ {TEGRA_GPIO_PV7, GPIOF_IN, "v7"},
+ {TEGRA_GPIO_PW0, GPIOF_IN, "w0"},
+ {TEGRA_GPIO_PD2, GPIOF_OUT_INIT_HIGH, "d2"},
+ {TEGRA_GPIO_PW1, GPIOF_IN, "w1"},
+ {TEGRA_GPIO_PB2, GPIOF_IN, "b2"},
+ {TEGRA_GPIO_PC1, GPIOF_IN, "c1"},
+ {TEGRA_GPIO_PC6, GPIOF_IN, "c6"},
+ {TEGRA_GPIO_PZ3, GPIOF_IN, "z3"},
+ {TEGRA_GPIO_PDD0, GPIOF_IN, "dd0"},
+ {TEGRA_GPIO_PDD4, GPIOF_IN, "dd4"},
+ {TEGRA_GPIO_PCC7, GPIOF_IN, "cc7"},
+ {TEGRA_GPIO_PDD7, GPIOF_IN, "dd7"},
+ {TEGRA_GPIO_PCC6, GPIOF_IN, "cc6"},
+ {TEGRA_GPIO_PDD3, GPIOF_IN, "dd3"},
+ {TEGRA_GPIO_PV2, GPIOF_IN, "v2"},
+ {TEGRA_GPIO_PA0, GPIOF_OUT_INIT_LOW, "a0"},
+ {TEGRA_GPIO_PR1, GPIOF_OUT_INIT_LOW, "r1"},
+ {TEGRA_GPIO_PR2, GPIOF_IN, "r2"},
+ {TEGRA_GPIO_PR3, GPIOF_IN, "r3"},
+ {TEGRA_GPIO_PR4, GPIOF_IN, "r4"},
+ {TEGRA_GPIO_PEE1, GPIOF_IN, "ee1"},
+ {TEGRA_GPIO_PT2, GPIOF_OUT_INIT_LOW, "t2"},
+ {TEGRA_GPIO_PT3, GPIOF_OUT_INIT_HIGH, "t3"},
+ {TEGRA_GPIO_PT1, GPIOF_IN, "t1"},
+};
+int __init e1853_gpio_init(void)
+{
+ int i, pin_count = 0;
+ struct gpio *gpios_info = NULL;
+ gpios_info = e1853_sku8_gpios;
+ pin_count = ARRAY_SIZE(e1853_sku8_gpios);
+
+ gpio_request_array(gpios_info, pin_count);
+ for (i = 0; i < pin_count; i++) {
+ gpio_export(gpios_info[i].gpio, true);
+ }
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-e1853-sdhci.c b/arch/arm/mach-tegra/board-e1853-sdhci.c
new file mode 100644
index 000000000000..5446bb46df15
--- /dev/null
+++ b/arch/arm/mach-tegra/board-e1853-sdhci.c
@@ -0,0 +1,83 @@
+/*
+ * arch/arm/mach-tegra/board-e1853-sdhci.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/resource.h>
+#include <linux/platform_device.h>
+#include <linux/wlan_plat.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach-types.h>
+#include <mach/irqs.h>
+#include <mach/iomap.h>
+#include <mach/sdhci.h>
+
+#include "gpio-names.h"
+#include "board.h"
+#include "board-e1853.h"
+#include "devices.h"
+
+static struct tegra_sdhci_platform_data tegra_sdhci_platform_data1 = {
+ .cd_gpio = -1,
+ .wp_gpio = -1,
+ .power_gpio = -1,
+ .is_8bit = false,
+};
+
+static struct tegra_sdhci_platform_data tegra_sdhci_platform_data2 = {
+ .cd_gpio = -1,
+ .wp_gpio = -1,
+ .power_gpio = -1,
+ .is_8bit = 1,
+ .mmc_data = {
+ .built_in = 1,
+ }
+};
+
+static struct tegra_sdhci_platform_data tegra_sdhci_platform_data3 = {
+ .cd_gpio = TEGRA_GPIO_PN6,
+ .wp_gpio = TEGRA_GPIO_PD4,
+ .power_gpio = TEGRA_GPIO_PN7,
+ .is_8bit = false,
+};
+
+static struct tegra_sdhci_platform_data tegra_sdhci_platform_data4 = {
+ .cd_gpio = -1,
+ .wp_gpio = -1,
+ .power_gpio = -1,
+ .is_8bit = true,
+};
+
+int __init e1853_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-e1853.c b/arch/arm/mach-tegra/board-e1853.c
new file mode 100644
index 000000000000..3b6d2bfc3d4c
--- /dev/null
+++ b/arch/arm/mach-tegra/board-e1853.c
@@ -0,0 +1,421 @@
+/*
+ * arch/arm/mach-tegra/board-e1853.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/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/serial_8250.h>
+#include <linux/i2c.h>
+#include <linux/i2c/panjit_ts.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/i2c-tegra.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <linux/platform_data/tegra_nor.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/partitions.h>
+#include <mach/clk.h>
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/pinmux.h>
+#include <mach/iomap.h>
+#include <mach/io.h>
+#include <mach/pci.h>
+#include <mach/audio.h>
+#include <mach/tegra_e1853_pdata.h>
+#include <asm/mach/flash.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/usb_phy.h>
+#include <sound/wm8903.h>
+#include <mach/tsensor.h>
+#include "board.h"
+#include "clock.h"
+#include "board-e1853.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "fuse.h"
+
+static __initdata struct tegra_clk_init_table e1853_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "pll_m", NULL, 0, true},
+ { "hda", "pll_p", 108000000, false},
+ { "hda2codec_2x", "pll_p", 48000000, false},
+ { "pwm", "clk_32k", 32768, false},
+ { "blink", "clk_32k", 32768, true},
+ { "pll_a", NULL, 552960000, false},
+ /* audio cif clock should be faster than i2s */
+ { "pll_a_out0", NULL, 24576000, false},
+ { "d_audio", "pll_a_out0", 24576000, false},
+ { "nor", "pll_p", 86500000, true},
+ { "uarta", "pll_p", 480000000, true},
+ { "uartb", "pll_p", 480000000, true},
+ { "uartc", "pll_p", 480000000, true},
+ { "uartd", "pll_p", 480000000, true},
+ { "sdmmc2", "pll_p", 52000000, true},
+ { "sbc2", "pll_m", 100000000, true},
+ { "sbc3", "pll_m", 100000000, true},
+ { "sbc4", "pll_m", 100000000, true},
+ { "sbc5", "pll_m", 100000000, true},
+ { "sbc6", "pll_m", 100000000, true},
+ { "cpu_g", "cclk_g", 900000000, true},
+ { "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},
+ { "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},
+ { "apbif", "clk_m", 12000000, false},
+ { "dam0", "clk_m", 12000000, true},
+ { "dam1", "clk_m", 12000000, true},
+ { "dam2", "clk_m", 12000000, true},
+ { "vi", "pll_p", 470000000, false},
+ { "vi_sensor", "pll_p", 150000000, false},
+ { "vde", "pll_c", 484000000, true},
+ { "host1x", "pll_c", 242000000, true},
+ { "mpe", "pll_c", 484000000, true},
+ { "se", "pll_m", 625000000, true},
+ { "i2c1", "pll_p", 3200000, true},
+ { "i2c2", "pll_p", 3200000, true},
+ { "i2c3", "pll_p", 3200000, true},
+ { "i2c4", "pll_p", 3200000, true},
+ { "i2c5", "pll_p", 3200000, true},
+ { "sdmmc2", "pll_p", 104000000, false},
+ {"wake.sclk", NULL, 334000000, true },
+ { NULL, NULL, 0, 0},
+};
+
+static struct tegra_i2c_platform_data e1853_i2c1_platform_data = {
+ .adapter_nr = 0,
+ .bus_count = 1,
+ .bus_clk_rate = { 100000, 0 },
+};
+
+static struct tegra_i2c_platform_data e1853_i2c2_platform_data = {
+ .adapter_nr = 1,
+ .bus_count = 1,
+ .bus_clk_rate = { 100000, 0 },
+ .is_clkon_always = true,
+};
+
+static struct tegra_i2c_platform_data e1853_i2c4_platform_data = {
+ .adapter_nr = 3,
+ .bus_count = 1,
+ .bus_clk_rate = { 100000, 0 },
+};
+
+static struct tegra_i2c_platform_data e1853_i2c5_platform_data = {
+ .adapter_nr = 4,
+ .bus_count = 1,
+ .bus_clk_rate = { 100000, 0 },
+};
+
+static struct tegra_pci_platform_data e1853_pci_platform_data = {
+ .port_status[0] = 1,
+ .port_status[1] = 1,
+ .port_status[2] = 1,
+ .use_dock_detect = 0,
+ .gpio = 0,
+};
+
+static void e1853_pcie_init(void)
+{
+ tegra_pci_device.dev.platform_data = &e1853_pci_platform_data;
+ platform_device_register(&tegra_pci_device);
+}
+
+static void e1853_i2c_init(void)
+{
+ tegra_i2c_device1.dev.platform_data = &e1853_i2c1_platform_data;
+ tegra_i2c_device2.dev.platform_data = &e1853_i2c2_platform_data;
+ tegra_i2c_device4.dev.platform_data = &e1853_i2c4_platform_data;
+ tegra_i2c_device5.dev.platform_data = &e1853_i2c5_platform_data;
+
+ platform_device_register(&tegra_i2c_device5);
+ platform_device_register(&tegra_i2c_device4);
+ platform_device_register(&tegra_i2c_device2);
+ platform_device_register(&tegra_i2c_device1);
+}
+
+static struct platform_device *e1853_uart_devices[] __initdata = {
+ &tegra_uarta_device,
+ &tegra_uartb_device,
+ &tegra_uartc_device,
+ &tegra_uartd_device,
+};
+static struct clk *debug_uart_clk;
+
+static void __init uart_debug_init(void)
+{
+ /* UARTA is the debug port. */
+ pr_info("Selecting UARTA as the debug console\n");
+ e1853_uart_devices[0] = &debug_uarta_device;
+ debug_uart_clk = clk_get_sys("serial8250.0", "uarta");
+}
+
+static void __init e1853_uart_init(void)
+{
+ /* Register low speed only if it is selected */
+ if (!is_tegra_debug_uartport_hs()) {
+ uart_debug_init();
+ /* Clock enable for the debug channel */
+ if (!IS_ERR_OR_NULL(debug_uart_clk)) {
+ pr_info("The debug console clock name is %s\n",
+ debug_uart_clk->name);
+ clk_enable(debug_uart_clk);
+ clk_set_rate(debug_uart_clk, 408000000);
+ } else {
+ pr_err("Not getting the clock %s for debug console\n",
+ debug_uart_clk->name);
+ }
+ }
+
+ platform_add_devices(e1853_uart_devices,
+ ARRAY_SIZE(e1853_uart_devices));
+}
+
+#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV)
+static struct spi_board_info tegra_spi_devices[] __initdata = {
+ {
+ .modalias = "spidev",
+ .bus_num = 1,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 18000000,
+ .platform_data = NULL,
+ .irq = 0,
+ },
+ {
+ .modalias = "spidev",
+ .bus_num = 2,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 18000000,
+ .platform_data = NULL,
+ .irq = 0,
+ },
+ {
+ .modalias = "spidev",
+ .bus_num = 4,
+ .chip_select = 2,
+ .mode = SPI_MODE_0,
+ .max_speed_hz = 18000000,
+ .platform_data = NULL,
+ .irq = 0,
+ },
+};
+
+static void __init e1853_register_spidev(void)
+{
+ spi_register_board_info(tegra_spi_devices,
+ ARRAY_SIZE(tegra_spi_devices));
+}
+#else
+#define e1853_register_spidev() do {} while (0)
+#endif
+
+
+static void e1853_spi_init(void)
+{
+ tegra_spi_device3.name = "spi_slave_tegra";
+ platform_device_register(&tegra_spi_device2);
+ platform_device_register(&tegra_spi_device3);
+ platform_device_register(&tegra_spi_device5);
+ e1853_register_spidev();
+}
+
+static struct platform_device tegra_camera = {
+ .name = "tegra_camera",
+ .id = -1,
+};
+
+static struct platform_device *e1853_devices[] __initdata = {
+#if defined(CONFIG_TEGRA_IOVMM_SMMU)
+ &tegra_smmu_device,
+#endif
+#if defined(CONFIG_TEGRA_AVP)
+ &tegra_avp_device,
+#endif
+ &tegra_camera,
+ &tegra_wdt0_device
+};
+
+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,
+ },
+ .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_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,
+ },
+ .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,
+ },
+ .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 e1853_usb_init(void)
+{
+ tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata;
+ platform_device_register(&tegra_ehci1_device);
+
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
+ platform_device_register(&tegra_ehci2_device);
+
+ tegra_ehci3_device.dev.platform_data = &tegra_ehci3_utmi_pdata;
+ platform_device_register(&tegra_ehci3_device);
+}
+
+static struct tegra_nor_platform_data e1853_nor_data = {
+ .flash = {
+ .map_name = "cfi_probe",
+ .width = 2,
+ },
+ .chip_parms = {
+ .MuxMode = NorMuxMode_ADMux,
+ .BurstLength = NorBurstLength_CntBurst,
+ .ReadMode = NorReadMode_Async,
+ .ReadyActive = NorReadyActive_BeforeData,
+ /* FIXME: Need to use characterized value */
+ .timing_default = {
+ .timing0 = 0xA0A05585,
+ .timing1 = 0x200A0406,
+ },
+ .timing_read = {
+ .timing0 = 0xA0A05585,
+ .timing1 = 0x00050406,
+ },
+ },
+};
+
+static void e1853_nor_init(void)
+{
+ tegra_nor_device.resource[2].end = TEGRA_NOR_FLASH_BASE + SZ_64M - 1;
+ tegra_nor_device.dev.platform_data = &e1853_nor_data;
+ platform_device_register(&tegra_nor_device);
+}
+
+static void __init tegra_e1853_init(void)
+{
+ tegra_init_board_info();
+ tegra_clk_init_from_table(e1853_clk_init_table);
+ e1853_pinmux_init();
+ e1853_i2c_init();
+ e1853_gpio_init();
+ e1853_uart_init();
+ e1853_usb_init();
+ e1853_sdhci_init();
+ e1853_spi_init();
+ platform_add_devices(e1853_devices, ARRAY_SIZE(e1853_devices));
+ e1853_panel_init();
+ e1853_nor_init();
+ e1853_pcie_init();
+}
+
+static void __init tegra_e1853_reserve(void)
+{
+#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
+ tegra_reserve(0, SZ_8M, SZ_8M);
+#else
+ tegra_reserve(SZ_128M, SZ_8M, SZ_8M);
+#endif
+}
+
+MACHINE_START(E1853, "e1853")
+ .boot_params = 0x80000100,
+ .init_irq = tegra_init_irq,
+ .init_early = tegra_init_early,
+ .init_machine = tegra_e1853_init,
+ .map_io = tegra_map_common_io,
+ .reserve = tegra_e1853_reserve,
+ .timer = &tegra_timer,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-e1853.h b/arch/arm/mach-tegra/board-e1853.h
new file mode 100644
index 000000000000..58b8ab8725af
--- /dev/null
+++ b/arch/arm/mach-tegra/board-e1853.h
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/mach-tegra/e1853/board-e1853.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/>.
+ */
+
+#ifndef _MACH_TEGRA_BOARD_E1853_H
+#define _MACH_TEGRA_BOARD_E1853_H
+
+int e1853_sdhci_init(void);
+int e1853_pinmux_init(void);
+int e1853_panel_init(void);
+int e1853_gpio_init(void);
+int e1853_pins_state_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/board-enterprise-memory.c b/arch/arm/mach-tegra/board-enterprise-memory.c
index 36a8264c2a21..1fc0d3c3fddd 100644
--- a/arch/arm/mach-tegra/board-enterprise-memory.c
+++ b/arch/arm/mach-tegra/board-enterprise-memory.c
@@ -116,7 +116,7 @@ static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000164, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00050001, /* MC_EMEM_ARB_CFG */
+ 0x00050002, /* MC_EMEM_ARB_CFG */
0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -236,7 +236,7 @@ static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800001c2, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00020001, /* MC_EMEM_ARB_CFG */
+ 0x00030003, /* MC_EMEM_ARB_CFG */
0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -356,7 +356,7 @@ static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
+ 0x00010003, /* MC_EMEM_ARB_CFG */
0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -476,7 +476,7 @@ static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -596,7 +596,7 @@ static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -716,7 +716,7 @@ static const struct tegra_emc_table enterprise_emc_tables_kmmll0_a02[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000ce6, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000006, /* MC_EMEM_ARB_CFG */
+ 0x0000000c, /* MC_EMEM_ARB_CFG */
0xc0000048, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000002, /* MC_EMEM_ARB_TIMING_RCD */
0x00000003, /* MC_EMEM_ARB_TIMING_RP */
diff --git a/arch/arm/mach-tegra/board-enterprise-panel.c b/arch/arm/mach-tegra/board-enterprise-panel.c
index 837635bf0731..c27201171e4b 100644
--- a/arch/arm/mach-tegra/board-enterprise-panel.c
+++ b/arch/arm/mach-tegra/board-enterprise-panel.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise-panel.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
@@ -169,6 +169,16 @@ static int enterprise_backlight_notify(struct device *unused, int brightness)
static int enterprise_disp1_check_fb(struct device *dev, struct fb_info *info);
+static struct platform_pwm_backlight_data external_pwm_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,
+};
+
#if IS_EXTERNAL_PWM
static struct platform_pwm_backlight_data enterprise_disp1_backlight_data = {
.pwm_id = 3,
@@ -214,10 +224,21 @@ static struct platform_device enterprise_disp1_backlight_device = {
},
};
+static struct platform_device external_pwm_disp1_backlight_device = {
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .platform_data = &external_pwm_disp1_backlight_data,
+ },
+};
#ifdef CONFIG_TEGRA_DC
static int enterprise_hdmi_vddio_enable(void)
{
int ret;
+ struct board_info board_info;
+
+ tegra_get_board_info(&board_info);
+
if (!enterprise_hdmi_vddio) {
enterprise_hdmi_vddio = regulator_get(NULL, "hdmi_5v0");
if (IS_ERR_OR_NULL(enterprise_hdmi_vddio)) {
@@ -234,16 +255,40 @@ static int enterprise_hdmi_vddio_enable(void)
enterprise_hdmi_vddio = NULL;
return ret;
}
+ if (board_info.board_id == BOARD_E1239) {
+ ret = gpio_request(TEGRA_GPIO_PM4, "en_hdmi_buffers");
+ if (ret < 0) {
+ pr_err("%s: gpio_request failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = gpio_direction_output(TEGRA_GPIO_PM4, 1);
+ if (ret < 0) {
+ pr_err("%s: gpio_direction_ouput failed %d\n",
+ __func__, ret);
+ gpio_free(TEGRA_GPIO_PM4);
+ return ret;
+ }
+ }
+
return ret;
}
static int enterprise_hdmi_vddio_disable(void)
{
+ struct board_info board_info;
+
+ tegra_get_board_info(&board_info);
+
if (enterprise_hdmi_vddio) {
regulator_disable(enterprise_hdmi_vddio);
regulator_put(enterprise_hdmi_vddio);
enterprise_hdmi_vddio = NULL;
}
+ if (board_info.board_id == BOARD_E1239) {
+ gpio_set_value(TEGRA_GPIO_PM4, 0);
+ gpio_free(TEGRA_GPIO_PM4);
+ }
return 0;
}
@@ -530,12 +575,10 @@ static int enterprise_dsi_panel_enable(void)
if (ret)
return ret;
-#if IS_EXTERNAL_PWM
- tegra_gpio_disable(enterprise_bl_pwm);
-#endif
#if DSI_PANEL_RESET
- if (board_info.fab >= BOARD_FAB_A03) {
+ if ((board_info.fab >= BOARD_FAB_A03) ||
+ (board_info.board_id == BOARD_E1239)) {
if (enterprise_lcd_reg == NULL) {
enterprise_lcd_reg = regulator_get(NULL, "lcd_vddio_en");
if (IS_ERR_OR_NULL(enterprise_lcd_reg)) {
@@ -554,16 +597,13 @@ static int enterprise_dsi_panel_enable(void)
}
}
- if (kernel_1st_panel_init != true) {
+ if (kernel_1st_panel_init == true) {
ret = gpio_request(enterprise_dsi_panel_reset, "panel reset");
if (ret < 0)
return ret;
-
- ret = gpio_direction_output(enterprise_dsi_panel_reset, 0);
- if (ret < 0) {
- gpio_free(enterprise_dsi_panel_reset);
- return ret;
- }
+ kernel_1st_panel_init = false;
+ } else {
+ gpio_direction_output(enterprise_dsi_panel_reset, 0);
gpio_set_value(enterprise_dsi_panel_reset, 0);
udelay(2000);
@@ -581,10 +621,7 @@ static int enterprise_dsi_panel_disable(void)
regulator_disable(enterprise_lcd_reg);
#if DSI_PANEL_RESET
- if (kernel_1st_panel_init != true) {
- gpio_free(enterprise_dsi_panel_reset);
- } else
- kernel_1st_panel_init = false;
+ gpio_direction_output(enterprise_dsi_panel_reset, 0);
#endif
return 0;
}
@@ -824,6 +861,13 @@ static struct platform_device *enterprise_gfx_devices[] __initdata = {
#endif
};
+static struct platform_device *external_pwm_gfx_devices[] __initdata = {
+#if defined(CONFIG_TEGRA_NVMAP)
+ &enterprise_nvmap_device,
+#endif
+ &tegra_pwfm3_device,
+};
+
static struct platform_device *enterprise_bl_devices[] = {
&enterprise_disp1_backlight_device,
};
@@ -871,14 +915,22 @@ int __init enterprise_panel_init(void)
BUILD_BUG_ON(ARRAY_SIZE(enterprise_bl_output_measured_a03) != 256);
BUILD_BUG_ON(ARRAY_SIZE(enterprise_bl_output_measured_a02) != 256);
- if (board_info.fab >= BOARD_FAB_A03) {
+ if (board_info.board_id != BOARD_E1239) {
+ if (board_info.fab >= BOARD_FAB_A03) {
#if !(IS_EXTERNAL_PWM)
- enterprise_disp1_backlight_data.clk_div = 0x1D;
+ enterprise_disp1_backlight_data.clk_div = 0x1D;
#endif
- bl_output = enterprise_bl_output_measured_a03;
- } else
- bl_output = enterprise_bl_output_measured_a02;
-
+ bl_output = enterprise_bl_output_measured_a03;
+ } else
+ bl_output = enterprise_bl_output_measured_a02;
+ } else {
+ enterprise_sd_settings.bl_device =
+ &external_pwm_disp1_backlight_device;
+ enterprise_bl_devices[0] =
+ &external_pwm_disp1_backlight_device;
+ bl_output =
+ enterprise_bl_output_measured_a03;
+ }
enterprise_dsi.chip_id = tegra_get_chipid();
enterprise_dsi.chip_rev = tegra_get_revision();
@@ -890,13 +942,25 @@ int __init enterprise_panel_init(void)
gpio_request(enterprise_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(enterprise_hdmi_hpd);
- 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);
+ if (board_info.board_id != BOARD_E1239) {
+ 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);
- gpio_request(enterprise_lcd_swp_pl, "lcd_swp_pl");
- gpio_direction_output(enterprise_lcd_swp_pl, 0);
- enterprise_stereo_set_orientation(enterprise_stereo.orientation);
+ 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 IS_EXTERNAL_PWM
+ gpio_request(enterprise_bl_pwm, "bl_pwm");
+ gpio_free(enterprise_bl_pwm);
+#endif
+ } else {
+ /* External pwm is used but do not use IS_EXTERNAL_PWM
+ compiler switch for TAI */
+ gpio_request(enterprise_bl_pwm, "bl_pwm");
+ gpio_free(enterprise_bl_pwm);
+ }
#if !(DC_CTRL_MODE & TEGRA_DC_OUT_ONE_SHOT_MODE)
gpio_request(enterprise_lcd_swp_pl, "lcd_te");
@@ -916,9 +980,13 @@ int __init enterprise_panel_init(void)
return err;
#endif
- err = platform_add_devices(enterprise_gfx_devices,
- ARRAY_SIZE(enterprise_gfx_devices));
-
+ if (board_info.board_id != BOARD_E1239) {
+ err = platform_add_devices(enterprise_gfx_devices,
+ ARRAY_SIZE(enterprise_gfx_devices));
+ } else {
+ err = platform_add_devices(external_pwm_gfx_devices,
+ ARRAY_SIZE(external_pwm_gfx_devices));
+ }
#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
res = nvhost_get_resource_byname(&enterprise_disp1_device,
IORESOURCE_MEM, "fbmem");
diff --git a/arch/arm/mach-tegra/board-enterprise-pinmux.c b/arch/arm/mach-tegra/board-enterprise-pinmux.c
index 721eb0d27576..efbdeb337e15 100644
--- a/arch/arm/mach-tegra/board-enterprise-pinmux.c
+++ b/arch/arm/mach-tegra/board-enterprise-pinmux.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise-pinmux.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
@@ -84,6 +84,9 @@ static __initdata struct tegra_drive_pingroup_config enterprise_drive_pinmux[] =
/* UART3 */
SET_DRIVE(UART3, DISABLE, ENABLE, DIV_1, 31, 31, FASTEST, FASTEST),
+
+ /* SDMMC1 */
+ SET_DRIVE(SDIO1, DISABLE, DISABLE, DIV_1, 46, 42, FAST, FAST),
};
#define DEFAULT_PINMUX(_pingroup, _mux, _pupd, _tri, _io) \
@@ -153,7 +156,6 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
/* SDMMC4 pinmux */
DEFAULT_PINMUX(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC4_DAT0, SDMMC4, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC4_DAT1, SDMMC4, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC4_DAT2, SDMMC4, PULL_UP, NORMAL, INPUT),
@@ -192,47 +194,7 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
DEFAULT_PINMUX(ULPI_DATA5, ULPI, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(ULPI_DATA6, ULPI, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(ULPI_DATA7, ULPI, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(ULPI_CLK, ULPI, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(ULPI_DIR, ULPI, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(ULPI_NXT, ULPI, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(ULPI_STP, ULPI, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_PWR1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_CS0_N, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_DC0, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT),
- 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, 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),
- DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D22, RSVD1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_CS1_N, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_M1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(LCD_DC1, DISPLAYA, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(VI_D0, RSVD1, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(VI_D1, SDMMC2, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(VI_D2, SDMMC2, NORMAL, NORMAL, INPUT),
@@ -243,84 +205,27 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
DEFAULT_PINMUX(VI_D10, RSVD1, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(VI_MCLK, VI, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(UART2_RTS_N, UARTB, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(UART2_CTS_N, UARTB, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(UART3_TXD, UARTC, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(UART3_CTS_N, UARTC, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(UART3_RTS_N, UARTC, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GPIO_PU0, UARTA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GPIO_PU1, UARTA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PU2, UARTA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PU3, UARTA, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GPIO_PU4, PWM1, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(GPIO_PU5, PWM2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PU6, PWM3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP4_FS, I2S3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP4_DIN, I2S3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP4_DOUT, I2S3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP4_SCLK, I2S3, NORMAL, NORMAL, INPUT),
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),
- DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, OUTPUT),
- DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PBB7, I2S4, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PCC2, I2S4, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(KB_ROW0, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_ROW1, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_ROW2, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_ROW3, KBC, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(KB_COL0, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_COL1, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_COL2, KBC, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(KB_COL3, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_COL4, KBC, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(KB_COL5, KBC, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(GPIO_PV0, RSVD, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(CLK_32K_OUT, BLINK, PULL_DOWN, TRISTATE, OUTPUT),
DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP1_FS, I2S0, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP1_DIN, I2S0, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP1_DOUT, I2S0, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP1_SCLK, I2S0, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(CLK1_REQ, DAP, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, INPUT),
-#if 0 /* For HDA realtek Codec */
- DEFAULT_PINMUX(SPDIF_IN, DAP2, PULL_DOWN, NORMAL, INPUT),
-#else
- DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, NORMAL, INPUT),
-#endif
-#if 0 /* For HDA realtek Codec */
- DEFAULT_PINMUX(DAP2_FS, HDA, PULL_DOWN, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP2_DIN, HDA, PULL_DOWN, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP2_DOUT, HDA, PULL_DOWN, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP2_SCLK, HDA, PULL_DOWN, NORMAL, INPUT),
-#else
- DEFAULT_PINMUX(DAP2_FS, I2S1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP2_DIN, I2S1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP2_DOUT, I2S1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(DAP2_SCLK, I2S1, NORMAL, NORMAL, INPUT),
-#endif
DEFAULT_PINMUX(SPI2_CS1_N, SPI2, PULL_UP, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI1_MOSI, SPI1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI1_SCK, SPI1, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SPI1_MISO, SPI1, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(PEX_L0_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(PEX_L0_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(PEX_L0_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
@@ -333,25 +238,8 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
DEFAULT_PINMUX(PEX_L2_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
CEC_PINMUX(HDMI_CEC, CEC, NORMAL, TRISTATE, OUTPUT, DEFAULT, DISABLE),
DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, TRISTATE, INPUT),
-
- /* Gpios */
- /* SDMMC1 CD gpio */
- DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_UP, NORMAL, INPUT),
- /* SDMMC1 WP gpio */
DEFAULT_PINMUX(VI_D11, RSVD1, PULL_UP, NORMAL, INPUT),
-
- /* Touch panel GPIO */
- /* Touch IRQ */
- DEFAULT_PINMUX(GMI_AD12, NAND, NORMAL, NORMAL, INPUT),
-
- /* Touch RESET */
- DEFAULT_PINMUX(GMI_AD14, NAND, NORMAL, NORMAL, INPUT),
-
DEFAULT_PINMUX(GMI_AD15, NAND, PULL_UP, TRISTATE, INPUT),
-
- /* Power rails GPIO */
- DEFAULT_PINMUX(KB_ROW8, KBC, PULL_UP, NORMAL, INPUT),
-
VI_PINMUX(VI_D6, VI, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D8, SDMMC2, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
VI_PINMUX(VI_D9, SDMMC2, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
@@ -363,6 +251,97 @@ static __initdata struct tegra_pingroup_config enterprise_pinmux_common[] = {
static __initdata struct tegra_pingroup_config enterprise_pinmux_a03[] = {
DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_CLK, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DIR, ULPI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_NXT, ULPI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(ULPI_STP, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR1, DISPLAYA, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(LCD_CS0_N, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_DC0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D5, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D6, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D7, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D8, DISPLAYA, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(LCD_D9, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D11, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D12, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D22, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_CS1_N, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_M1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_DC1, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_RTS_N, UARTB, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_CTS_N, UARTB, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(UART3_TXD, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(UART3_CTS_N, UARTC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(UART3_RTS_N, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU0, UARTA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU1, UARTA, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GPIO_PU2, UARTA, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GPIO_PU3, UARTA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU4, PWM1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU5, PWM2, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GPIO_PU6, PWM3, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(DAP4_FS, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DIN, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DOUT, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_SCLK, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A16, UARTD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_A17, UARTD, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GMI_A18, UARTD, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PCC1, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB0, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB7, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PCC2, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_COL3, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, PULL_UP, TRISTATE, INPUT),
+ DEFAULT_PINMUX(DAP1_FS, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DIN, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DOUT, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_SCLK, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(DAP2_FS, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DIN, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DOUT, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_SCLK, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MOSI, SPI1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_SCK, SPI1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_MISO, SPI1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_UP, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GMI_AD12, NAND, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(GMI_AD14, NAND, NORMAL, TRISTATE, INPUT),
+ DEFAULT_PINMUX(KB_ROW8, KBC, PULL_UP, TRISTATE, INPUT),
};
static __initdata struct tegra_pingroup_config enterprise_unused_pinmux_common[] = {
@@ -423,15 +402,108 @@ static __initdata struct tegra_pingroup_config enterprise_unused_pinmux_common[]
DEFAULT_PINMUX(SPI2_MISO, SPI2, PULL_DOWN, TRISTATE, OUTPUT),
};
-static __initdata struct tegra_pingroup_config enterprise_unused_pinmux_a02[] = {
- DEFAULT_PINMUX(LCD_D10, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
- DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+static __initdata struct tegra_pingroup_config enterprise_pinmux_a02[] = {
+ DEFAULT_PINMUX(LCD_D10, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_CLK, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DIR, ULPI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_NXT, ULPI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_STP, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_CS0_N, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DC0, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT),
+ 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, 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),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D22, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_CS1_N, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_M1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_DC1, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_RTS_N, UARTB, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_CTS_N, UARTB, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_TXD, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_CTS_N, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_RTS_N, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU0, UARTA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU1, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU2, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU3, UARTA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU4, PWM1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU5, PWM2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU6, PWM3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_FS, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DIN, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DOUT, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_SCLK, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A16, UARTD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_A17, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A18, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB7, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PCC2, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL3, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_FS, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DIN, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DOUT, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_SCLK, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_FS, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DIN, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DOUT, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_SCLK, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MOSI, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_SCK, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MISO, SPI1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD12, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD14, NAND, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW8, KBC, PULL_UP, NORMAL, INPUT),
};
static struct tegra_gpio_table gpio_table[] = {
{ .gpio = TEGRA_GPIO_HP_DET, .enable = true },
};
-
+static struct tegra_gpio_table tai_gpio_table[] = {
+ { .gpio = TEGRA_GPIO_CODEC_RST, .enable = true },
+};
struct pin_info_low_power_mode {
char name[16];
int gpio_nr;
@@ -512,6 +584,367 @@ static __initdata struct pin_info_low_power_mode enterprise_unused_gpio_pins_a02
PIN_GPIO_LPM("LCD_PWR0", TEGRA_GPIO_PB2, 0, 0),
};
+static __initdata struct pin_info_low_power_mode enterprise_gpio_pins_a03[] = {
+ PIN_GPIO_LPM("GPIO_PV3", TEGRA_GPIO_PV3, 0, 0),
+ PIN_GPIO_LPM("LCD_DC0", TEGRA_GPIO_PN6, 0, 0),
+ PIN_GPIO_LPM("LCD_D5", TEGRA_GPIO_PE5, 0, 0),
+ PIN_GPIO_LPM("LCD_D20", TEGRA_GPIO_PM4, 0, 0),
+ PIN_GPIO_LPM("LCD_DC1", TEGRA_GPIO_PD2, 0, 0),
+ PIN_GPIO_LPM("GPIO_PU4", TEGRA_GPIO_PU4, 0, 0),
+ PIN_GPIO_LPM("KB_COL3", TEGRA_GPIO_PQ3, 0, 0),
+ PIN_GPIO_LPM("SPI1_MOSI", TEGRA_GPIO_PX4, 0, 0),
+ PIN_GPIO_LPM("SPI1_MISO", TEGRA_GPIO_PX7, 0, 0),
+ PIN_GPIO_LPM("SPI1_SCK", TEGRA_GPIO_PX5, 0, 0),
+};
+/*******************************TAI pinmux (E1239) ************************/
+static __initdata struct tegra_pingroup_config tai_pinmux_common[] = {
+ /* SDMMC1 pinmux */
+ DEFAULT_PINMUX(SDMMC1_CLK, SDMMC1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_CMD, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT3, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT2, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT1, SDMMC1, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC1_DAT0, SDMMC1, 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(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT0, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT1, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT2, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT3, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT4, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT5, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT6, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_DAT7, SDMMC4, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC4_RST_N, RSVD1, PULL_DOWN, NORMAL, INPUT),
+
+ /* I2C1 pinmux */
+ I2C_PINMUX(GEN1_I2C_SCL, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(GEN1_I2C_SDA, I2C1, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* I2C2 pinmux */
+ I2C_PINMUX(GEN2_I2C_SCL, I2C2, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(GEN2_I2C_SDA, I2C2, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* I2C3 pinmux */
+ I2C_PINMUX(CAM_I2C_SCL, I2C3, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(CAM_I2C_SDA, I2C3, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ /* I2C4 pinmux */
+ I2C_PINMUX(DDC_SCL, I2C4, PULL_UP, NORMAL, INPUT, DISABLE, DISABLE),
+ I2C_PINMUX(DDC_SDA, I2C4, PULL_UP, NORMAL, INPUT, DISABLE, DISABLE),
+
+ /* Power I2C pinmux */
+ I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+ I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DISABLE, ENABLE),
+
+ DEFAULT_PINMUX(ULPI_DATA0, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA1, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA2, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA3, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA4, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA5, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA6, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DATA7, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_CLK, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(ULPI_DIR, ULPI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_NXT, ULPI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(ULPI_STP, ULPI, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_FS, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DIN, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_DOUT, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV2, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PV3, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_CS0_N, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DC0, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_DE, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D2, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D3, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D4, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D5, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D6, RSVD1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D7, RSVD1, NORMAL, NORMAL, OUTPUT),
+ 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, OUTPUT),
+ DEFAULT_PINMUX(LCD_D13, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D14, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D15, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D16, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D17, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D18, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D20, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D21, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D22, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_D23, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_CS1_N, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_DC1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(VI_D0, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D1, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D2, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D3, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D4, VI, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(VI_D5, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D7, SDMMC2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_D10, RSVD1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(VI_MCLK, VI, PULL_UP, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART2_TXD, IRDA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_RTS_N, UARTB, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART2_CTS_N, UARTB, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_TXD, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(UART3_RXD, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_CTS_N, UARTC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(UART3_RTS_N, UARTC, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU0, UARTA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU1, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU2, UARTA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU3, UARTA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU4, PWM1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PU5, PWM2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PU6, PWM3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_FS, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DIN, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_DOUT, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP4_SCLK, I2S3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_AD11, PWM3, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_A16, UARTD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_A17, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A18, UARTD, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GMI_A19, UARTD, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PCC1, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB0, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PBB7, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PCC2, I2S4, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(JTAG_RTCK, RTCK, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW0, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW1, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW2, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW3, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW10, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_ROW12, KBC, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL0, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL1, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL2, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL3, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL4, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(KB_COL5, KBC, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(GPIO_PV0, RSVD, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK_32K_OUT, BLINK, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(OWR, OWR, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_FS, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DIN, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_DOUT, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP1_SCLK, I2S0, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK1_REQ, DAP, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(CLK1_OUT, EXTPERIPH1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPDIF_IN, SPDIF, NORMAL, NORMAL, INPUT),
+
+
+ DEFAULT_PINMUX(SPI2_CS1_N, INVALID, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(PEX_L0_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L0_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(PEX_L0_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_WAKE_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L1_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L1_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(PEX_L1_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_PRSNT_N, PCIE, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(PEX_L2_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(PEX_L2_CLKREQ_N, PCIE, NORMAL, NORMAL, INPUT),
+ CEC_PINMUX(HDMI_CEC, CEC, NORMAL, TRISTATE, OUTPUT, DEFAULT, DISABLE),
+ DEFAULT_PINMUX(HDMI_INT, RSVD0, NORMAL, TRISTATE, INPUT),
+
+ /* Gpios */
+ /* SDMMC1 CD gpio */
+ DEFAULT_PINMUX(GMI_IORDY, RSVD1, PULL_UP, NORMAL, INPUT),
+ /* SDMMC1 WP gpio */
+ DEFAULT_PINMUX(VI_D11, RSVD1, PULL_UP, NORMAL, INPUT),
+
+ /* Touch RESET */
+ DEFAULT_PINMUX(GMI_AD14, NAND, NORMAL, NORMAL, INPUT),
+
+ DEFAULT_PINMUX(GMI_AD15, NAND, PULL_UP, TRISTATE, INPUT),
+
+ /* Power rails GPIO */
+ DEFAULT_PINMUX(KB_ROW8, KBC, PULL_UP, NORMAL, INPUT),
+
+ VI_PINMUX(VI_D6, VI, NORMAL, NORMAL, OUTPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D8, SDMMC2, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_D9, SDMMC2, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_PCLK, RSVD1, PULL_UP, TRISTATE, INPUT, DISABLE, ENABLE),
+ VI_PINMUX(VI_HSYNC, RSVD1, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+ VI_PINMUX(VI_VSYNC, RSVD1, NORMAL, NORMAL, INPUT, DISABLE, DISABLE),
+
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_D10, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(GMI_CS7_N, NAND_ALT, PULL_UP, TRISTATE, INPUT),
+ DEFAULT_PINMUX(SPI2_MOSI, SPI6, PULL_UP, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(CLK3_OUT, EXTPERIPH3, NORMAL, NORMAL, OUTPUT),
+};
+
+static __initdata struct tegra_pingroup_config tai_pinmux_a02[] = {
+ DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(LCD_PWR1, DISPLAYA, NORMAL, NORMAL, INPUT),
+};
+
+static __initdata struct tegra_pingroup_config tai_pinmux_a03[] = {
+ DEFAULT_PINMUX(LCD_PWR2, DISPLAYA, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(LCD_PWR1, DISPLAYA, NORMAL, NORMAL, OUTPUT),
+};
+
+static __initdata struct tegra_pingroup_config tai_unused_pinmux_common[] = {
+ DEFAULT_PINMUX(CLK2_OUT, EXTPERIPH2, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CLK2_REQ, DAP, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CLK3_REQ, DEV3, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CLK_32K_OUT, BLINK, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB4, VGP4, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB5, VGP5, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GPIO_PBB6, VGP6, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD0, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD1, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD2, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD3, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD4, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD5, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD6, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD7, GMI, NORMAL, TRISTATE, OUTPUT),
+ 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),
+ DEFAULT_PINMUX(GMI_CS6_N, GMI, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_CLK, GMI, NORMAL, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_DQS, RSVD3, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_RST_N, GMI, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_WAIT, GMI, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_WP_N, GMI, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW6, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW7, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW9, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW11, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW13, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW14, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(KB_ROW15, KBC, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_WR_N, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_HSYNC, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_VSYNC, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_SCK, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_SDOUT, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_SDIN, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CRT_HSYNC, CRT, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(CRT_VSYNC, CRT, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT6, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT7, SDMMC3, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPDIF_OUT, SPDIF, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_SCK, SPI2, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_MISO, SPI2, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI2_CS0_N, SPI2, PULL_DOWN, TRISTATE, OUTPUT),
+
+ DEFAULT_PINMUX(LCD_D19, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(LCD_M1, DISPLAYA, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD8, PWM0, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD9, PWM1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD10, PWM2, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD12, RSVD1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(GMI_AD13, RSVD1, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(DAP2_FS, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DIN, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(DAP2_DOUT, I2S1, NORMAL, NORMAL, OUTPUT),
+ DEFAULT_PINMUX(DAP2_SCLK, I2S1, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SPI1_MOSI, SPI2, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_SCK , SPI2, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_MISO , INVALID, PULL_DOWN, TRISTATE, OUTPUT),
+ DEFAULT_PINMUX(SPI1_CS0_N, SPI1, PULL_DOWN, TRISTATE, OUTPUT),
+};
+
+static __initdata struct pin_info_low_power_mode
+tai_unused_gpio_pins_common[] = {
+ PIN_GPIO_LPM("CLK2_OUT", TEGRA_GPIO_PW5, 0, 0),
+ PIN_GPIO_LPM("CLK2_REQ", TEGRA_GPIO_PCC5, 0, 0),
+ PIN_GPIO_LPM("CLK3_REQ", TEGRA_GPIO_PEE1, 0, 0),
+ PIN_GPIO_LPM("CLK_32K_OUT", TEGRA_GPIO_PA0, 0, 0),
+ PIN_GPIO_LPM("GPIO_PBB4", TEGRA_GPIO_PBB4, 0, 0),
+ PIN_GPIO_LPM("GPIO_PBB5", TEGRA_GPIO_PBB5, 0, 0),
+ PIN_GPIO_LPM("GPIO_PBB6", TEGRA_GPIO_PBB6, 0, 0),
+ PIN_GPIO_LPM("GMI_AD0", TEGRA_GPIO_PG0, 0, 0),
+ PIN_GPIO_LPM("GMI_AD1", TEGRA_GPIO_PG1, 0, 0),
+ PIN_GPIO_LPM("GMI_AD2", TEGRA_GPIO_PG2, 0, 0),
+ PIN_GPIO_LPM("GMI_AD3", TEGRA_GPIO_PG3, 0, 0),
+ PIN_GPIO_LPM("GMI_AD4", TEGRA_GPIO_PG4, 0, 0),
+ 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),
+ 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),
+ PIN_GPIO_LPM("GMI_CS6_N", TEGRA_GPIO_PI3, 0, 0),
+ PIN_GPIO_LPM("GMI_CLK", TEGRA_GPIO_PK1, 0, 0),
+ PIN_GPIO_LPM("GMI_DQS", TEGRA_GPIO_PI2, 0, 0),
+ PIN_GPIO_LPM("GMI_RST_N", TEGRA_GPIO_PI4, 0, 0),
+ PIN_GPIO_LPM("GMI_WAIT", TEGRA_GPIO_PI7, 0, 0),
+ PIN_GPIO_LPM("GMI_WP_N", TEGRA_GPIO_PC7, 0, 0),
+ PIN_GPIO_LPM("KB_ROW6", TEGRA_GPIO_PR6, 0, 0),
+ PIN_GPIO_LPM("KB_ROW7", TEGRA_GPIO_PR7, 0, 0),
+ PIN_GPIO_LPM("KB_ROW9", TEGRA_GPIO_PS1, 0, 0),
+ PIN_GPIO_LPM("KB_ROW11", TEGRA_GPIO_PS3, 0, 0),
+ PIN_GPIO_LPM("KB_ROW13", TEGRA_GPIO_PS5, 0, 0),
+ PIN_GPIO_LPM("KB_ROW14", TEGRA_GPIO_PS6, 0, 0),
+ PIN_GPIO_LPM("KB_ROW15", TEGRA_GPIO_PS7, 0, 0),
+ PIN_GPIO_LPM("LCD_PCLK", TEGRA_GPIO_PB3, 0, 0),
+ PIN_GPIO_LPM("LCD_WR_N", TEGRA_GPIO_PZ3, 0, 0),
+ PIN_GPIO_LPM("LCD_HSYNC", TEGRA_GPIO_PJ3, 0, 0),
+ PIN_GPIO_LPM("LCD_VSYNC", TEGRA_GPIO_PJ4, 0, 0),
+ PIN_GPIO_LPM("LCD_SCK", TEGRA_GPIO_PZ4, 0, 0),
+ PIN_GPIO_LPM("LCD_SDOUT", TEGRA_GPIO_PN5, 0, 0),
+ PIN_GPIO_LPM("LCD_SDIN", TEGRA_GPIO_PZ2, 0, 0),
+ PIN_GPIO_LPM("CRT_HSYNC", TEGRA_GPIO_PV6, 0, 0),
+ PIN_GPIO_LPM("CRT_VSYNC", TEGRA_GPIO_PV7, 0, 0),
+ PIN_GPIO_LPM("SDMMC3_DAT4", TEGRA_GPIO_PD1, 0, 0),
+ PIN_GPIO_LPM("SDMMC3_DAT5", TEGRA_GPIO_PD0, 0, 0),
+ PIN_GPIO_LPM("SDMMC3_DAT6", TEGRA_GPIO_PD3, 0, 0),
+ PIN_GPIO_LPM("SDMMC3_DAT7", TEGRA_GPIO_PD4, 0, 0),
+ PIN_GPIO_LPM("SPDIF_OUT", TEGRA_GPIO_PK5, 0, 0),
+ PIN_GPIO_LPM("SPI1_CS0_N", TEGRA_GPIO_PX6, 0, 0),
+ PIN_GPIO_LPM("SPI2_SCK", TEGRA_GPIO_PX2, 0, 0),
+ PIN_GPIO_LPM("SPI2_MISO", TEGRA_GPIO_PX1, 0, 0),
+ PIN_GPIO_LPM("SPI2_CS0_N", TEGRA_GPIO_PX3, 0, 0),
+ PIN_GPIO_LPM("LCD_D19", TEGRA_GPIO_PM3, 0, 0),
+ PIN_GPIO_LPM("LCD_M1", TEGRA_GPIO_PW1, 0, 0),
+ PIN_GPIO_LPM("GMI_AD8", TEGRA_GPIO_PH0, 0, 0),
+ PIN_GPIO_LPM("GMI_AD9", TEGRA_GPIO_PH1, 0, 0),
+ PIN_GPIO_LPM("GMI_AD10", TEGRA_GPIO_PH2, 0, 0),
+ PIN_GPIO_LPM("GMI_AD12", TEGRA_GPIO_PH4, 0, 0),
+ PIN_GPIO_LPM("GMI_AD13", TEGRA_GPIO_PH5, 0, 0),
+ PIN_GPIO_LPM("DAP2_FS", TEGRA_GPIO_PA2, 0, 0),
+ PIN_GPIO_LPM("DAP2_DIN", TEGRA_GPIO_PA4, 0, 0),
+ PIN_GPIO_LPM("DAP2_DOUT", TEGRA_GPIO_PA5, 0, 0),
+ PIN_GPIO_LPM("DAP2_SCLK", TEGRA_GPIO_PA3, 0, 0),
+ PIN_GPIO_LPM("SPI1_MOSI", TEGRA_GPIO_PX4, 0, 0),
+ PIN_GPIO_LPM("SPI1_SCK", TEGRA_GPIO_PX5, 0, 0),
+ PIN_GPIO_LPM("SPI1_MISO", TEGRA_GPIO_PX7, 0, 0),
+
+};
+
static void enterprise_set_unused_pin_gpio(struct pin_info_low_power_mode *lpm_pin_info,
int list_count)
{
@@ -549,25 +982,51 @@ int __init enterprise_pinmux_init(void)
struct board_info board_info;
tegra_get_board_info(&board_info);
- tegra_pinmux_config_table(enterprise_pinmux_common,
+ if (board_info.board_id != BOARD_E1239) {
+ tegra_pinmux_config_table(enterprise_pinmux_common,
ARRAY_SIZE(enterprise_pinmux_common));
- tegra_drive_pinmux_config_table(enterprise_drive_pinmux,
- ARRAY_SIZE(enterprise_drive_pinmux));
- tegra_pinmux_config_table(enterprise_unused_pinmux_common,
+ tegra_drive_pinmux_config_table(enterprise_drive_pinmux,
+ ARRAY_SIZE(enterprise_drive_pinmux));
+ tegra_pinmux_config_table(enterprise_unused_pinmux_common,
ARRAY_SIZE(enterprise_unused_pinmux_common));
- tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
- enterprise_set_unused_pin_gpio(enterprise_unused_gpio_pins_common,
- ARRAY_SIZE(enterprise_unused_gpio_pins_common));
+ tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
+ enterprise_set_unused_pin_gpio(
+ enterprise_unused_gpio_pins_common,
+ ARRAY_SIZE(enterprise_unused_gpio_pins_common));
- if (board_info.fab < BOARD_FAB_A03) {
- tegra_pinmux_config_table(enterprise_unused_pinmux_a02,
- ARRAY_SIZE(enterprise_unused_pinmux_a02));
- enterprise_set_unused_pin_gpio(enterprise_unused_gpio_pins_a02,
- ARRAY_SIZE(enterprise_unused_gpio_pins_a02));
- } else {
- tegra_pinmux_config_table(enterprise_pinmux_a03,
+ if (board_info.fab < BOARD_FAB_A03) {
+ tegra_pinmux_config_table(enterprise_pinmux_a02,
+ ARRAY_SIZE(enterprise_pinmux_a02));
+ enterprise_set_unused_pin_gpio(
+ enterprise_unused_gpio_pins_a02,
+ ARRAY_SIZE(enterprise_unused_gpio_pins_a02));
+ } else {
+ tegra_pinmux_config_table(enterprise_pinmux_a03,
ARRAY_SIZE(enterprise_pinmux_a03));
+ enterprise_set_unused_pin_gpio(enterprise_gpio_pins_a03,
+ ARRAY_SIZE(enterprise_gpio_pins_a03));
+ }
+ } else {
+ tegra_pinmux_config_table(tai_pinmux_common,
+ ARRAY_SIZE(tai_pinmux_common));
+ if (board_info.fab <= BOARD_FAB_A02) {
+ tegra_pinmux_config_table(tai_pinmux_a02,
+ ARRAY_SIZE(tai_pinmux_a02));
+ } else {
+ tegra_pinmux_config_table(tai_pinmux_a03,
+ ARRAY_SIZE(tai_pinmux_a03));
+ }
+ tegra_drive_pinmux_config_table(enterprise_drive_pinmux,
+ ARRAY_SIZE(enterprise_drive_pinmux));
+ tegra_pinmux_config_table(tai_unused_pinmux_common,
+ ARRAY_SIZE(tai_unused_pinmux_common));
+
+ tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
+ tegra_gpio_config(tai_gpio_table, ARRAY_SIZE(tai_gpio_table));
+ enterprise_set_unused_pin_gpio(tai_unused_gpio_pins_common,
+ ARRAY_SIZE(tai_unused_gpio_pins_common));
+
}
return 0;
diff --git a/arch/arm/mach-tegra/board-enterprise-power.c b/arch/arm/mach-tegra/board-enterprise-power.c
index bbe39ec4ad3e..3475452adc5a 100644
--- a/arch/arm/mach-tegra/board-enterprise-power.c
+++ b/arch/arm/mach-tegra/board-enterprise-power.c
@@ -140,6 +140,13 @@ static struct regulator_consumer_supply tps80031_smps4_supply_a03[] = {
REGULATOR_SUPPLY("vddf_core_emmc", NULL),
};
+static struct regulator_consumer_supply tps80031_smps4_supply_tai[] = {
+ REGULATOR_SUPPLY("vddio_sdmmc_2v85", NULL),
+ REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL),
+ REGULATOR_SUPPLY("vdd_ddr_rx", NULL),
+ REGULATOR_SUPPLY("vddf_core_emmc", NULL),
+};
+
static struct regulator_consumer_supply tps80031_vana_supply_a02[] = {
REGULATOR_SUPPLY("unused_vana", NULL),
};
@@ -233,28 +240,30 @@ static struct regulator_consumer_supply tps80031_battery_charge_supply[] = {
REGULATOR_SUPPLY("usb_bat_chg", NULL),
};
-#define TPS_PDATA_INIT(_id, _sname, _minmv, _maxmv, _supply_reg, _always_on, \
+#define TPS_PDATA_INIT(_reg_id, _id, _sname, _minmv, _maxmv, _supply_reg, _always_on, \
_boot_on, _apply_uv, _init_uV, _init_enable, _init_apply, \
_flags, _ectrl, _delay) \
- static struct tps80031_regulator_platform_data pdata_##_id##_##_sname = { \
- .regulator = { \
- .constraints = { \
- .min_uV = (_minmv)*1000, \
- .max_uV = (_maxmv)*1000, \
- .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
- REGULATOR_MODE_STANDBY), \
- .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
- REGULATOR_CHANGE_STATUS | \
- REGULATOR_CHANGE_VOLTAGE), \
- .always_on = _always_on, \
- .boot_on = _boot_on, \
- .apply_uV = _apply_uv, \
- }, \
- .num_consumer_supplies = \
- ARRAY_SIZE(tps80031_##_id##_supply_##_sname), \
- .consumer_supplies = tps80031_##_id##_supply_##_sname, \
- .supply_regulator = _supply_reg, \
+ static struct regulator_init_data reg_idata_##_id##_##_sname = { \
+ .constraints = { \
+ .name = tps80031_rails(_id), \
+ .min_uV = (_minmv)*1000, \
+ .max_uV = (_maxmv)*1000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ .always_on = _always_on, \
+ .boot_on = _boot_on, \
+ .apply_uV = _apply_uv, \
}, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(tps80031_##_id##_supply_##_sname), \
+ .consumer_supplies = tps80031_##_id##_supply_##_sname, \
+ }; \
+ static struct tps80031_regulator_platform_data pdata_##_id##_##_sname = { \
+ .reg_init_data = &reg_idata_##_id##_##_sname, \
+ .regulator_id = TPS80031_REGULATOR_##_reg_id, \
.init_uV = _init_uV * 1000, \
.init_enable = _init_enable, \
.init_apply = _init_apply, \
@@ -263,31 +272,32 @@ static struct regulator_consumer_supply tps80031_battery_charge_supply[] = {
.delay_us = _delay, \
}
-TPS_PDATA_INIT(vio, a02, 600, 2100, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0);
-TPS_PDATA_INIT(vio, a03, 600, 2100, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0);
-TPS_PDATA_INIT(smps1, common, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ2 | PWR_OFF_ON_SLEEP, 0);
-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, 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, 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, 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_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);
+TPS_PDATA_INIT(VIO, vio, a02, 600, 2100, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(VIO, vio, a03, 600, 2100, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(SMPS1, smps1, common, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ2 | PWR_OFF_ON_SLEEP, 0);
+TPS_PDATA_INIT(SMPS2, smps2, common, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(SMPS3, smps3, common, 600, 2100, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(SMPS4, smps4, a02, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(SMPS4, smps4, a03, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(SMPS4, smps4, tai, 600, 2100, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(LDO1, ldo1, a02, 1000, 3300, tps80031_rails(vio), 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(LDO1, ldo1, a03, 1000, 3300, tps80031_rails(vio), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDO2, ldo2, common, 1000, 1000, 0, 1, 1, 1, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(LDO3, ldo3, common, 1000, 3300, tps80031_rails(vio), 0, 0, 0, -1, 0, 0, 0, PWR_OFF_ON_SLEEP, 0);
+TPS_PDATA_INIT(LDO4, ldo4, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(LDO4, ldo4, a03, 1000, 3300, tps80031_rails(vio), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDO5, ldo5, common, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(LDO6, ldo6, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDO6, ldo6, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDO7, ldo7, a02, 1000, 3300, tps80031_rails(vio), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDO7, ldo7, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDOLN, ldoln, a02, 1000, 3300, tps80031_rails(smps3), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDOLN, ldoln, a03, 1000, 3300, tps80031_rails(vio), 0, 0, 0, -1, 0, 0, 0, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(LDOUSB, ldousb, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, USBLDO_INPUT_VSYS, PWR_OFF_ON_SLEEP, 0);
+TPS_PDATA_INIT(LDOUSB, ldousb, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, USBLDO_INPUT_VSYS, PWR_REQ_INPUT_PREQ1, 0);
+TPS_PDATA_INIT(VANA, vana, a02, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0);
+TPS_PDATA_INIT(VANA, vana, a03, 1000, 3300, 0, 0, 0, 0, -1, 0, 0, 0, PWR_OFF_ON_SLEEP, 0);
+TPS_PDATA_INIT(VBUS, 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 = {
.irq = ENT_TPS80031_IRQ_BASE + TPS80031_INT_RTC_ALARM,
@@ -331,74 +341,62 @@ static struct tps80031_bg_platform_data battery_gauge_data = {
.battery_present = 1,
};
-#define TPS_RTC() \
- { \
- .id = 0, \
- .name = "rtc_tps80031", \
- .platform_data = &rtc_data, \
- }
-
-#define TPS_REG(_id, _data, _sname) \
- { \
- .id = TPS80031_ID_##_id, \
- .name = "tps80031-regulator", \
- .platform_data = &pdata_##_data##_##_sname, \
- }
-#define TPS_BATTERY() \
- { \
- .name = "tps80031-charger", \
- .platform_data = &bcharger_pdata, \
- }
-#define TPS_BATTERY_GAUGE() \
- { \
- .name = "tps80031-battery-gauge", \
- .platform_data = &battery_gauge_data, \
- }
-#define TPS_GPADC() \
- { \
- .name = "tps80031-gpadc", \
- }
-
-#define TPS80031_DEVS_COMMON \
- TPS_REG(SMPS1, smps1, common), \
- TPS_REG(SMPS2, smps2, common), \
- TPS_REG(SMPS3, smps3, common), \
- TPS_REG(LDO2, ldo2, common), \
- TPS_REG(LDO3, ldo3, common), \
- TPS_REG(LDO5, ldo5, common), \
- TPS_REG(VBUS, vbus, common), \
- TPS_RTC(), \
- TPS_BATTERY(), \
- TPS_BATTERY_GAUGE(), \
- TPS_GPADC()
-
-
-static struct tps80031_subdev_info tps80031_devs_a02[] = {
- TPS_REG(VIO, vio, a02),
- TPS80031_DEVS_COMMON,
- TPS_REG(SMPS4, smps4, a02),
- TPS_REG(LDO1, ldo1, a02),
- TPS_REG(LDO4, ldo4, a02),
- TPS_REG(LDO6, ldo6, 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[] = {
- TPS_REG(VIO, vio, a03),
- TPS80031_DEVS_COMMON,
- TPS_REG(SMPS4, smps4, a03),
- TPS_REG(LDO1, ldo1, a03),
- TPS_REG(LDO4, ldo4, a03),
- TPS_REG(LDO6, ldo6, a03),
- TPS_REG(LDO7, ldo7, a03),
- TPS_REG(LDOLN, ldoln, a03),
- TPS_REG(LDOUSB, ldousb, a03),
- TPS_REG(VANA, vana, a03),
-
+#define TPS_REG_PDATA(_id, _sname) &pdata_##_id##_##_sname
+static struct tps80031_regulator_platform_data *tps80031_reg_pdata_a02[] = {
+ TPS_REG_PDATA(vio, a02),
+ TPS_REG_PDATA(smps1, common),
+ TPS_REG_PDATA(smps2, common),
+ TPS_REG_PDATA(smps3, common),
+ TPS_REG_PDATA(ldo2, common),
+ TPS_REG_PDATA(ldo3, common),
+ TPS_REG_PDATA(ldo5, common),
+ TPS_REG_PDATA(vbus, common),
+ TPS_REG_PDATA(smps4, a02),
+ TPS_REG_PDATA(ldo1, a02),
+ TPS_REG_PDATA(ldo4, a02),
+ TPS_REG_PDATA(ldo6, a02),
+ TPS_REG_PDATA(ldo7, a02),
+ TPS_REG_PDATA(ldoln, a02),
+ TPS_REG_PDATA(ldousb, a02),
+ TPS_REG_PDATA(vana, a02),
+};
+
+static struct tps80031_regulator_platform_data *tps80031_reg_pdata_a03[] = {
+ TPS_REG_PDATA(vio, a03),
+ TPS_REG_PDATA(smps1, common),
+ TPS_REG_PDATA(smps2, common),
+ TPS_REG_PDATA(smps3, common),
+ TPS_REG_PDATA(ldo2, common),
+ TPS_REG_PDATA(ldo3, common),
+ TPS_REG_PDATA(ldo5, common),
+ TPS_REG_PDATA(vbus, common),
+ TPS_REG_PDATA(smps4, a03),
+ TPS_REG_PDATA(ldo1, a03),
+ TPS_REG_PDATA(ldo4, a03),
+ TPS_REG_PDATA(ldo6, a03),
+ TPS_REG_PDATA(ldo7, a03),
+ TPS_REG_PDATA(ldoln, a03),
+ TPS_REG_PDATA(ldousb, a03),
+ TPS_REG_PDATA(vana, a03),
+};
+
+static struct tps80031_regulator_platform_data *tps80031_reg_pdata_tai[] = {
+ TPS_REG_PDATA(vio, a03),
+ TPS_REG_PDATA(smps1, common),
+ TPS_REG_PDATA(smps2, common),
+ TPS_REG_PDATA(smps3, common),
+ TPS_REG_PDATA(ldo2, common),
+ TPS_REG_PDATA(ldo3, common),
+ TPS_REG_PDATA(ldo5, common),
+ TPS_REG_PDATA(vbus, common),
+ TPS_REG_PDATA(smps4, tai),
+ TPS_REG_PDATA(ldo1, a03),
+ TPS_REG_PDATA(ldo4, a03),
+ TPS_REG_PDATA(ldo6, a03),
+ TPS_REG_PDATA(ldo7, a03),
+ TPS_REG_PDATA(ldoln, a03),
+ TPS_REG_PDATA(ldousb, a03),
+ TPS_REG_PDATA(vana, a03),
};
static struct tps80031_clk32k_init_data clk32k_idata[] = {
@@ -444,6 +442,9 @@ static struct tps80031_platform_data tps_platform = {
.clk32k_init_data = clk32k_idata,
.clk32k_init_data_size = ARRAY_SIZE(clk32k_idata),
.use_power_off = true,
+ .rtc_pdata = &rtc_data,
+ .bg_pdata = &battery_gauge_data,
+ .battery_charger_pdata = &bcharger_pdata,
};
static struct i2c_board_info __initdata enterprise_regulators[] = {
@@ -472,6 +473,10 @@ static struct regulator_consumer_supply fixed_reg_pmu_3v3_en_supply[] = {
static struct regulator_consumer_supply fixed_reg_pmu_hdmi_5v0_en_supply[] = {
REGULATOR_SUPPLY("hdmi_5v0", NULL),
};
+static struct regulator_consumer_supply
+fixed_reg_pmu_hdmi_5v0_en_tai_supply[] = {
+ REGULATOR_SUPPLY("hdmi_5v0", NULL),
+};
/* LCD-D16 (GPIO M0) from T30*/
static struct regulator_consumer_supply fixed_reg_vdd_fuse_en_supply[] = {
@@ -594,7 +599,7 @@ static struct gpio gpio_reg_sdmmc3_vdd_sel_gpios[] = {
}, \
}
-GPIO_REG(4, sdmmc3_vdd_sel, tps80031_rails(SMPS4),
+GPIO_REG(4, sdmmc3_vdd_sel, tps80031_rails(smps4),
true, false, 0, 1000, 3300);
/* Macro for defining fixed regulator sub device data */
@@ -653,26 +658,33 @@ FIXED_REG(7, vdd_sdmmc3_2v85_en, NULL,
FIXED_REG(8, lcd_1v8_en, NULL,
TEGRA_GPIO_PB2, true, 1800, 0, 0);
-#define ADD_FIXED_REG(_name) (&fixed_reg_##_name##_dev)
-
-#define FIXED_REGS_COMMON \
- ADD_FIXED_REG(pmu_5v15_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)
+FIXED_REG(9, pmu_hdmi_5v0_en_tai, NULL,
+ ENT_TPS80031_GPIO_SYSEN, true, 5000, 0, 0);
+#define ADD_FIXED_REG(_name) (&fixed_reg_##_name##_dev)
static struct platform_device *fixed_regs_devices_a02[] = {
- 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(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[] = {
- FIXED_REGS_COMMON,
+ ADD_FIXED_REG(pmu_5v15_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),
+ ADD_FIXED_REG(vdd_sdmmc3_2v85_en),
+ ADD_FIXED_REG(lcd_1v8_en),
+};
+
+static struct platform_device *fixed_regs_devices_tai[] = {
+ ADD_FIXED_REG(pmu_hdmi_5v0_en_tai),
+ ADD_FIXED_REG(cam_ldo_2v8_en),
+ ADD_FIXED_REG(cam_ldo_1v8_en),
ADD_FIXED_REG(vdd_sdmmc3_2v85_en),
ADD_FIXED_REG(lcd_1v8_en),
};
@@ -690,14 +702,18 @@ static int __init enterprise_fixed_regulator_init(void)
tegra_get_board_info(&board_info);
- if (board_info.fab < BOARD_FAB_A03) {
- fixed_regs_devices = fixed_regs_devices_a02;
- nfixreg_devs = ARRAY_SIZE(fixed_regs_devices_a02);
+ if (board_info.board_id == BOARD_E1239) {
+ fixed_regs_devices = fixed_regs_devices_tai;
+ nfixreg_devs = ARRAY_SIZE(fixed_regs_devices_tai);
} else {
- fixed_regs_devices = fixed_regs_devices_a03;
- nfixreg_devs = ARRAY_SIZE(fixed_regs_devices_a03);
+ if (board_info.fab < BOARD_FAB_A03) {
+ fixed_regs_devices = fixed_regs_devices_a02;
+ nfixreg_devs = ARRAY_SIZE(fixed_regs_devices_a02);
+ } else {
+ fixed_regs_devices = fixed_regs_devices_a03;
+ nfixreg_devs = ARRAY_SIZE(fixed_regs_devices_a03);
+ }
}
-
return platform_add_devices(fixed_regs_devices, nfixreg_devs);
}
@@ -741,6 +757,9 @@ int __init enterprise_regulator_init(void)
pmc_dpd_pads = readl(pmc + PMC_DPD_PADS_ORIDE);
writel(pmc_dpd_pads & ~PMC_DPD_PADS_ORIDE_BLINK , pmc + PMC_DPD_PADS_ORIDE);
+ /* Setting CPU voltage tolerance in lower side for 3000uV */
+ pdata_smps1_common.tolerance_uv = 3000;
+
/* Disable battery charging if power adapter is connected. */
if (get_power_supply_type() == POWER_SUPPLY_TYPE_MAINS) {
bcharger_pdata.num_consumer_supplies = 0;
@@ -748,14 +767,21 @@ 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;
+ if ((board_info.fab < BOARD_FAB_A03) &&
+ (board_info.board_id != BOARD_E1239)) {
+ tps_platform.num_regulator_pdata = ARRAY_SIZE(tps80031_reg_pdata_a02);
+ tps_platform.regulator_pdata = tps80031_reg_pdata_a02;
} else {
- tps_platform.num_subdevs = ARRAY_SIZE(tps80031_devs_a03);
- tps_platform.subdevs = tps80031_devs_a03;
+ if (machine_is_tai()) {
+ tps_platform.num_regulator_pdata =
+ ARRAY_SIZE(tps80031_reg_pdata_tai);
+ tps_platform.regulator_pdata =
+ tps80031_reg_pdata_tai;
+ } else {
+ tps_platform.num_regulator_pdata =
+ ARRAY_SIZE(tps80031_reg_pdata_a03);
+ tps_platform.regulator_pdata = tps80031_reg_pdata_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;
@@ -788,6 +814,15 @@ static struct tegra_suspend_platform_data enterprise_suspend_data = {
.sysclkreq_high = true,
.board_suspend = enterprise_board_suspend,
.board_resume = enterprise_board_resume,
+#ifdef CONFIG_TEGRA_LP1_950
+ .lp1_lowvolt_support = true,
+ .i2c_base_addr = TEGRA_I2C5_BASE,
+ .pmuslave_addr = 0x24,
+ .core_reg_addr = 0x5B,
+ .lp1_core_volt_low = 0x1D,
+ .lp1_core_volt_high = 0x33,
+#endif
+ .cpu_wake_freq = CPU_WAKE_FREQ_LOW,
};
static void enterprise_init_deep_sleep_mode(void)
@@ -799,6 +834,7 @@ static void enterprise_init_deep_sleep_mode(void)
enterprise_suspend_data.suspend_mode = TEGRA_SUSPEND_LP1;
if ((bi.board_id == BOARD_E1205 && (bi.sku & BOARD_SKU_VF_BIT) == 0) ||
+ (bi.board_id == BOARD_E1239 && (bi.sku & BOARD_SKU_VF_BIT) == 0) ||
(bi.board_id == BOARD_E1197 && (bi.sku & BOARD_SKU_VF_BIT)))
enterprise_suspend_data.cpu_timer = 8000;
}
@@ -843,9 +879,9 @@ static struct platform_device enterprise_bpc_mgmt_device = {
void __init enterprise_bpc_mgmt_init(void)
{
+#ifdef CONFIG_SMP
int int_gpio = TEGRA_GPIO_TO_IRQ(TEGRA_BPC_TRIGGER);
-#ifdef CONFIG_SMP
cpumask_setall(&(bpc_mgmt_platform_data.affinity_mask));
irq_set_affinity_hint(int_gpio,
&(bpc_mgmt_platform_data.affinity_mask));
diff --git a/arch/arm/mach-tegra/board-enterprise-sdhci.c b/arch/arm/mach-tegra/board-enterprise-sdhci.c
index 7a5632601fe6..a003ae9cbd8e 100644
--- a/arch/arm/mach-tegra/board-enterprise-sdhci.c
+++ b/arch/arm/mach-tegra/board-enterprise-sdhci.c
@@ -22,11 +22,13 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/mmc/host.h>
+#include <linux/wl12xx.h>
#include <asm/mach-types.h>
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/sdhci.h>
+#include <mach/io_dpd.h>
#include "gpio-names.h"
#include "board.h"
@@ -51,6 +53,14 @@ static struct wifi_platform_data enterprise_wifi_control = {
.set_carddetect = enterprise_wifi_set_carddetect,
};
+static struct wl12xx_platform_data enterprise_wl12xx_wlan_data __initdata = {
+ .irq = TEGRA_GPIO_TO_IRQ(ENTERPRISE_WLAN_WOW),
+ .board_ref_clock = WL12XX_REFCLOCK_26,
+ .board_tcxo_clock = 1,
+ .set_power = enterprise_wifi_power,
+ .set_carddetect = enterprise_wifi_set_carddetect,
+};
+
static struct resource wifi_resource[] = {
[0] = {
.name = "bcm4329_wlan_irq",
@@ -60,7 +70,7 @@ static struct resource wifi_resource[] = {
},
};
-static struct platform_device enterprise_wifi_device = {
+static struct platform_device enterprise_brcm_wifi_device = {
.name = "bcm4329_wlan",
.id = 1,
.num_resources = 1,
@@ -221,11 +231,43 @@ static int enterprise_wifi_set_carddetect(int val)
static int enterprise_wifi_power(int on)
{
+ struct tegra_io_dpd *sd_dpd;
+
pr_debug("%s: %d\n", __func__, on);
- gpio_set_value(ENTERPRISE_WLAN_PWR, on);
- mdelay(100);
- gpio_set_value(ENTERPRISE_WLAN_RST, on);
- mdelay(200);
+
+ /*
+ * FIXME : we need to revisit IO DPD code
+ * on how should multiple pins under DPD get controlled
+ *
+ * enterprise GPIO WLAN enable is part of SDMMC1 pin group
+ */
+ sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device0.dev);
+ if (sd_dpd) {
+ mutex_lock(&sd_dpd->delay_lock);
+ tegra_io_dpd_disable(sd_dpd);
+ mutex_unlock(&sd_dpd->delay_lock);
+ }
+
+ if (on) {
+ gpio_set_value(ENTERPRISE_WLAN_RST, 1);
+ mdelay(100);
+ gpio_set_value(ENTERPRISE_WLAN_RST, 0);
+ mdelay(100);
+ gpio_set_value(ENTERPRISE_WLAN_RST, 1);
+ mdelay(100);
+ gpio_set_value(ENTERPRISE_WLAN_PWR, 1);
+ mdelay(200);
+ } else {
+ gpio_set_value(ENTERPRISE_WLAN_RST, 0);
+ mdelay(100);
+ gpio_set_value(ENTERPRISE_WLAN_PWR, 0);
+ }
+
+ if (sd_dpd) {
+ mutex_lock(&sd_dpd->delay_lock);
+ tegra_io_dpd_enable(sd_dpd);
+ mutex_unlock(&sd_dpd->delay_lock);
+ }
return 0;
}
@@ -274,7 +316,11 @@ static int __init enterprise_wifi_init(void)
if (rc)
pr_err("WLAN_WOW gpio direction configuration failed:%d\n", rc);
- platform_device_register(&enterprise_wifi_device);
+ if (tegra_get_commchip_id() == COMMCHIP_TI_WL18XX)
+ wl12xx_set_platform_data(&enterprise_wl12xx_wlan_data);
+ else
+ platform_device_register(&enterprise_brcm_wifi_device);
+
return 0;
}
@@ -285,6 +331,13 @@ int __init enterprise_sdhci_init(void)
tegra_sdhci_platform_data2.cd_gpio = ENTERPRISE_SD_CD;
platform_device_register(&tegra_sdhci_device2);
+ /* TI wifi module does not use emdedded sdio */
+ if (tegra_get_commchip_id() == COMMCHIP_TI_WL18XX) {
+#ifdef CONFIG_MMC_EMBEDDED_SDIO
+ tegra_sdhci_platform_data0.mmc_data.embedded_sdio = NULL;
+#endif
+ }
+
platform_device_register(&tegra_sdhci_device0);
enterprise_wifi_init();
return 0;
diff --git a/arch/arm/mach-tegra/board-enterprise-sensors.c b/arch/arm/mach-tegra/board-enterprise-sensors.c
index aab409b89ea9..c66d3fbbd1e8 100644
--- a/arch/arm/mach-tegra/board-enterprise-sensors.c
+++ b/arch/arm/mach-tegra/board-enterprise-sensors.c
@@ -40,16 +40,21 @@
#include <linux/platform_data/ina230.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/clk.h>
#include <mach/gpio.h>
#include <media/ar0832_main.h>
#include <media/tps61050.h>
#include <media/ov9726.h>
#include <mach/edp.h>
#include <mach/thermal.h>
+#include <mach/clk.h>
#include "cpu-tegra.h"
#include "gpio-names.h"
#include "board-enterprise.h"
#include "board.h"
+#include "clock.h"
+
+static struct board_info board_info;
static int nct_get_temp(void *_data, long *temp)
{
@@ -283,6 +288,14 @@ struct enterprise_power_rail {
static struct enterprise_power_rail ent_vicsi_pwr[NUM_OF_CAM];
+static __initdata struct tegra_clk_init_table tai_front_cam_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "extern3", "pll_p", 24000000, false},
+ { "clk_out_3", "extern3", 24000000, false},
+ { NULL, NULL, 0, 0},
+};
+
+
static int enterprise_cam_pwr(enum CAMERA_INDEX cam, bool pwr_on)
{
struct enterprise_power_rail *reg_cam = &ent_vicsi_pwr[cam];
@@ -357,7 +370,8 @@ static int enterprise_ar0832_ri_power_on(int is_stereo)
/* Release Reset */
if (is_stereo) {
gpio_set_value(CAM1_RST_L_GPIO, 1);
- gpio_set_value(CAM2_RST_L_GPIO, 1);
+ if (board_info.board_id != BOARD_E1239)
+ gpio_set_value(CAM2_RST_L_GPIO, 1);
} else
gpio_set_value(CAM1_RST_L_GPIO, 1);
/*
@@ -375,11 +389,12 @@ static int enterprise_ar0832_le_power_on(int is_stereo)
int ret = 0;
pr_info("%s: ++\n", __func__);
- ret = enterprise_cam_pwr(CAM_REAR_LEFT, true);
-
- /* Release Reset */
- gpio_set_value(CAM2_RST_L_GPIO, 1);
+ if (board_info.board_id != BOARD_E1239) {
+ ret = enterprise_cam_pwr(CAM_REAR_LEFT, true);
+ /* Release Reset */
+ gpio_set_value(CAM2_RST_L_GPIO, 1);
+ }
/*
It takes 2400 EXTCLK for ar0832 to be ready for I2c.
EXTCLK is 10 ~ 24MHz. 1 ms should be enough to cover
@@ -387,8 +402,10 @@ static int enterprise_ar0832_le_power_on(int is_stereo)
*/
enterprise_msleep(1);
- /* CSI B is shared between Front camera and Rear Left camera */
- gpio_set_value(CAM_CSI_MUX_SEL_GPIO, 1);
+ if (board_info.board_id != BOARD_E1239) {
+ /* CSI B is shared between Front camera and Rear Left camera */
+ gpio_set_value(CAM_CSI_MUX_SEL_GPIO, 1);
+ }
return ret;
}
@@ -403,7 +420,8 @@ static int enterprise_ar0832_ri_power_off(int is_stereo)
/* Assert Reset */
if (is_stereo) {
gpio_set_value(CAM1_RST_L_GPIO, 0);
- gpio_set_value(CAM2_RST_L_GPIO, 0);
+ if (board_info.board_id != BOARD_E1239)
+ gpio_set_value(CAM2_RST_L_GPIO, 0);
} else
gpio_set_value(CAM1_RST_L_GPIO, 0);
@@ -412,14 +430,15 @@ static int enterprise_ar0832_ri_power_off(int is_stereo)
static int enterprise_ar0832_le_power_off(int is_stereo)
{
- int ret;
-
- pr_info("%s: ++\n", __func__);
- ret = enterprise_cam_pwr(CAM_REAR_LEFT, false);
+ int ret = 0;
- /* Assert Reset */
- gpio_set_value(CAM2_RST_L_GPIO, 0);
+ if (board_info.board_id != BOARD_E1239) {
+ pr_info("%s: ++\n", __func__);
+ ret = enterprise_cam_pwr(CAM_REAR_LEFT, false);
+ /* Assert Reset */
+ gpio_set_value(CAM2_RST_L_GPIO, 0);
+ }
return ret;
}
@@ -427,10 +446,15 @@ static int enterprise_ov9726_power_on(void)
{
pr_info("ov9726 power on\n");
- /* switch mipi mux to front camera */
- gpio_set_value(CAM_CSI_MUX_SEL_GPIO, CAM_CSI_MUX_SEL_FRONT);
+ if (board_info.board_id != BOARD_E1239) {
+ /* switch mipi mux to front camera */
+ gpio_set_value(CAM_CSI_MUX_SEL_GPIO, CAM_CSI_MUX_SEL_FRONT);
+ }
enterprise_cam_pwr(CAM_FRONT, true);
+ if (board_info.board_id == BOARD_E1239)
+ clk_enable(tegra_get_clock_by_name("clk_out_3"));
+
return 0;
}
@@ -440,6 +464,9 @@ static int enterprise_ov9726_power_off(void)
enterprise_cam_pwr(CAM_FRONT, false);
+ if (board_info.board_id == BOARD_E1239)
+ clk_disable(tegra_get_clock_by_name("clk_out_3"));
+
return 0;
}
@@ -485,7 +512,13 @@ static struct enterprise_cam_gpio enterprise_cam_gpio_data[] = {
[5] = TEGRA_CAMERA_GPIO(CAM_FLASH_EN_GPIO, "flash_en", 1),
[6] = TEGRA_CAMERA_GPIO(CAM_I2C_MUX_RST_EXP, "cam_i2c_mux_rst", 1),
};
-
+static struct enterprise_cam_gpio tai_cam_gpio_data[] = {
+ [0] = TEGRA_CAMERA_GPIO(CAM1_RST_L_GPIO, "cam1_rst_lo", 0),
+ [1] = TEGRA_CAMERA_GPIO(CAM3_RST_L_GPIO, "cam3_rst_lo", 0),
+ [2] = TEGRA_CAMERA_GPIO(CAM3_PWDN_GPIO, "cam3_pwdn", 1),
+ [3] = TEGRA_CAMERA_GPIO(CAM_FLASH_EN_GPIO, "flash_en", 1),
+ [4] = TEGRA_CAMERA_GPIO(CAM_I2C_MUX_RST_EXP, "cam_i2c_mux_rst", 1),
+};
static struct pca954x_platform_mode enterprise_pca954x_modes[] = {
{ .adap_id = PCA954x_I2C_BUS0, .deselect_on_exit = true, },
{ .adap_id = PCA954x_I2C_BUS1, .deselect_on_exit = true, },
@@ -565,49 +598,87 @@ static struct i2c_board_info enterprise_i2c7_boardinfo[] = {
.platform_data = &enterprise_ar0832_ri_data,
},
};
+static struct i2c_board_info ar0832_i2c2_boardinfo_tai[] = {
+ {
+ /* 0x36: alternative slave address */
+ I2C_BOARD_INFO("ar0832", 0x36),
+ .platform_data = &enterprise_ar0832_ri_data,
+ },
+ {
+ I2C_BOARD_INFO("tps61050", 0x33),
+ .platform_data = &enterprise_tps61050_pdata,
+ },
+ {
+ I2C_BOARD_INFO("ov9726", OV9726_I2C_ADDR >> 1),
+ .platform_data = &enterprise_ov9726_data,
+ },
+};
static int enterprise_cam_init(void)
{
int ret;
int i;
- struct board_info bi;
struct board_info cam_bi;
bool i2c_mux = false;
pr_info("%s:++\n", __func__);
memset(ent_vicsi_pwr, 0, sizeof(ent_vicsi_pwr));
- for (i = 0; i < ARRAY_SIZE(enterprise_cam_gpio_data); i++) {
- ret = gpio_request(enterprise_cam_gpio_data[i].gpio,
- enterprise_cam_gpio_data[i].label);
- if (ret < 0) {
- pr_err("%s: gpio_request failed for gpio #%d\n",
- __func__, i);
- goto fail_free_gpio;
- }
- 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_get_board_info(&bi);
tegra_get_camera_board_info(&cam_bi);
- if (bi.board_id == BOARD_E1205) {
- if (bi.fab == BOARD_FAB_A00 || bi.fab == BOARD_FAB_A01)
+ if (board_info.board_id == BOARD_E1239) {
+ for (i = 0; i < ARRAY_SIZE(tai_cam_gpio_data); i++) {
+ ret = gpio_request(tai_cam_gpio_data[i].gpio,
+ tai_cam_gpio_data[i].label);
+ if (ret < 0) {
+ pr_err("%s: gpio_request failed for gpio #%d\n",
+ __func__, i);
+ goto fail_free_gpio;
+ }
+ gpio_direction_output(tai_cam_gpio_data[i].gpio,
+ tai_cam_gpio_data[i].value);
+ gpio_export(tai_cam_gpio_data[i].gpio, false);
+ }
+
+ tegra_clk_init_from_table(tai_front_cam_clk_init_table);
+
+ } else {
+ for (i = 0; i < ARRAY_SIZE(enterprise_cam_gpio_data); i++) {
+ ret = gpio_request(enterprise_cam_gpio_data[i].gpio,
+ enterprise_cam_gpio_data[i].label);
+ if (ret < 0) {
+ pr_err("%s: gpio_request failed for gpio #%d\n",
+ __func__, i);
+ goto fail_free_gpio;
+ }
+ gpio_direction_output(enterprise_cam_gpio_data[i].gpio,
+ enterprise_cam_gpio_data[i].value);
+ gpio_export(enterprise_cam_gpio_data[i].gpio, false);
+ }
+ }
+
+ if (board_info.board_id == BOARD_E1205) {
+ if (board_info.fab == BOARD_FAB_A00 ||
+ board_info.fab == BOARD_FAB_A01)
i2c_mux = false;
- else if (bi.fab == BOARD_FAB_A02)
+ else if (board_info.fab == BOARD_FAB_A02)
i2c_mux = true;
- } else if (bi.board_id == BOARD_E1197) {
+ } else if (board_info.board_id == BOARD_E1197) {
if (cam_bi.fab == BOARD_FAB_A00)
i2c_mux = false;
else if (cam_bi.fab == BOARD_FAB_A01)
i2c_mux = true;
}
- if (!i2c_mux)
- i2c_register_board_info(2, ar0832_i2c2_boardinfo,
- ARRAY_SIZE(ar0832_i2c2_boardinfo));
- else {
+ if (!i2c_mux) {
+ if (board_info.board_id == BOARD_E1239) {
+ i2c_register_board_info(2, ar0832_i2c2_boardinfo_tai,
+ ARRAY_SIZE(ar0832_i2c2_boardinfo));
+ } else {
+ i2c_register_board_info(2, ar0832_i2c2_boardinfo,
+ ARRAY_SIZE(ar0832_i2c2_boardinfo));
+ }
+ } else {
i2c_register_board_info(2, enterprise_i2c2_boardinfo,
ARRAY_SIZE(enterprise_i2c2_boardinfo));
/*
@@ -623,8 +694,14 @@ static int enterprise_cam_init(void)
fail_free_gpio:
pr_err("%s enterprise_cam_init failed!\n", __func__);
- while (i--)
- gpio_free(enterprise_cam_gpio_data[i].gpio);
+ if (board_info.board_id == BOARD_E1239) {
+ while (i--)
+ gpio_free(tai_cam_gpio_data[i].gpio);
+
+ } else {
+ while (i--)
+ gpio_free(enterprise_cam_gpio_data[i].gpio);
+ }
return ret;
}
@@ -657,9 +734,12 @@ int __init enterprise_sensors_init(void)
{
int ret;
+ tegra_get_board_info(&board_info);
+
enterprise_isl_init();
enterprise_nct1008_init();
- mpuirq_init();
+ if (board_info.board_id != BOARD_E1239)
+ mpuirq_init();
#if ENTERPRISE_INA230_ENABLED
enterprise_ina230_init();
#endif
diff --git a/arch/arm/mach-tegra/board-enterprise.c b/arch/arm/mach-tegra/board-enterprise.c
index 9c8890ed96cf..a85c2dccd1a3 100644
--- a/arch/arm/mach-tegra/board-enterprise.c
+++ b/arch/arm/mach-tegra/board-enterprise.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise.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
@@ -38,8 +38,12 @@
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/memblock.h>
#include <linux/rfkill-gpio.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#include <linux/mfd/tlv320aic3262-core.h>
#include <linux/nfc/pn544.h>
+#include <linux/skbuff.h>
+#include <linux/ti_wilink_st.h>
#include <sound/max98088.h>
#include <mach/clk.h>
@@ -48,6 +52,7 @@
#include <mach/pinmux.h>
#include <mach/iomap.h>
#include <mach/io.h>
+#include <mach/io_dpd.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/usb_phy.h>
@@ -121,6 +126,32 @@ static struct tegra_thermal_data thermal_data = {
#endif
};
+/* wl128x BT, FM, GPS connectivity chip */
+struct ti_st_plat_data enterprise_wilink_pdata = {
+ .nshutdown_gpio = TEGRA_GPIO_PE6,
+ .dev_name = BLUETOOTH_UART_DEV_NAME,
+ .flow_cntrl = 1,
+ .baud_rate = 3000000,
+};
+
+static struct platform_device wl128x_device = {
+ .name = "kim",
+ .id = -1,
+ .dev.platform_data = &enterprise_wilink_pdata,
+};
+
+static struct platform_device btwilink_device = {
+ .name = "btwilink",
+ .id = -1,
+};
+
+static noinline void __init enterprise_bt_st(void)
+{
+ pr_info("enterprise_bt_st");
+
+ platform_device_register(&wl128x_device);
+ platform_device_register(&btwilink_device);
+}
static struct rfkill_gpio_platform_data enterprise_bt_rfkill_pdata[] = {
{
.name = "bt_rfkill",
@@ -137,8 +168,21 @@ static struct platform_device enterprise_bt_rfkill_device = {
.platform_data = &enterprise_bt_rfkill_pdata,
},
};
-
-static struct resource enterprise_bluesleep_resources[] = {
+static struct resource enterprise_ti_bluesleep_resources[] = {
+ [0] = {
+ .name = "gpio_host_wake",
+ .start = TEGRA_GPIO_PS2,
+ .end = TEGRA_GPIO_PS2,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .name = "host_wake",
+ .start = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2),
+ .end = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PS2),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ },
+};
+static struct resource enterprise_brcm_bluesleep_resources[] = {
[0] = {
.name = "gpio_host_wake",
.start = TEGRA_GPIO_PS2,
@@ -159,16 +203,30 @@ static struct resource enterprise_bluesleep_resources[] = {
},
};
-static struct platform_device enterprise_bluesleep_device = {
+static struct platform_device enterprise_ti_bluesleep_device = {
.name = "bluesleep",
.id = -1,
- .num_resources = ARRAY_SIZE(enterprise_bluesleep_resources),
- .resource = enterprise_bluesleep_resources,
+ .num_resources = ARRAY_SIZE(enterprise_ti_bluesleep_resources),
+ .resource = enterprise_ti_bluesleep_resources,
};
+static struct platform_device enterprise_brcm_bluesleep_device = {
+ .name = "bluesleep",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(enterprise_brcm_bluesleep_resources),
+ .resource = enterprise_brcm_bluesleep_resources,
+};
+static void __init enterprise_bt_rfkill(void)
+{
+ platform_device_register(&enterprise_bt_rfkill_device);
+ return;
+}
static void __init enterprise_setup_bluesleep(void)
{
- platform_device_register(&enterprise_bluesleep_device);
+ if (tegra_get_commchip_id() == COMMCHIP_TI_WL18XX)
+ platform_device_register(&enterprise_ti_bluesleep_device);
+ else
+ platform_device_register(&enterprise_brcm_bluesleep_device);
return;
}
@@ -181,7 +239,6 @@ static __initdata struct tegra_clk_init_table enterprise_clk_init_table[] = {
{ "blink", "clk_32k", 32768, true},
{ "i2s0", "pll_a_out0", 0, false},
{ "i2s1", "pll_a_out0", 0, false},
- { "i2s2", "pll_a_out0", 0, false},
{ "i2s3", "pll_a_out0", 0, false},
{ "spdif_out", "pll_a_out0", 0, false},
{ "d_audio", "clk_m", 12000000, false},
@@ -194,9 +251,61 @@ static __initdata struct tegra_clk_init_table enterprise_clk_init_table[] = {
{ "audio3", "i2s3_sync", 0, false},
{ "vi", "pll_p", 0, false},
{ "vi_sensor", "pll_p", 0, false},
+ { "i2c5", "pll_p", 3200000, false},
{ NULL, NULL, 0, 0},
};
+static __initdata struct tegra_clk_init_table enterprise_clk_i2s2_table[] = {
+ /* name parent rate enabled */
+ { "i2s2", "pll_a_out0", 0, false},
+ { NULL, NULL, 0, 0},
+};
+
+static __initdata struct tegra_clk_init_table enterprise_clk_i2s4_table[] = {
+ /* name parent rate enabled */
+ { "i2s4", "pll_a_out0", 0, false},
+ { NULL, NULL, 0, 0},
+};
+
+static struct aic3262_gpio_setup aic3262_gpio[] = {
+ /* GPIO 1*/
+ {
+ .used = 1,
+ .in = 0,
+ .value = AIC3262_GPIO1_FUNC_INT1_OUTPUT ,
+ },
+ /* GPIO 2*/
+ {
+ .used = 1,
+ .in = 0,
+ .value = AIC3262_GPIO2_FUNC_ADC_MOD_CLK_OUTPUT,
+ },
+ /* GPIO 1 */
+ {
+ .used = 0,
+ },
+ {// GPI2
+ .used = 1,
+ .in = 1,
+ .in_reg = AIC3262_DMIC_INPUT_CNTL,
+ .in_reg_bitmask = AIC3262_DMIC_CONFIGURE_MASK,
+ .in_reg_shift = AIC3262_DMIC_CONFIGURE_SHIFT,
+ .value = AIC3262_DMIC_GPI2_LEFT_GPI2_RIGHT,
+ },
+ {// GPO1
+ .used = 0,
+ .value = AIC3262_GPO1_FUNC_DISABLED,
+ },
+};
+
+static struct aic3262_pdata aic3262_codec_pdata = {
+ .gpio_irq = 1,
+ .gpio_reset = TEGRA_GPIO_CODEC_RST,
+ .gpio = aic3262_gpio,
+ .naudint_irq = TEGRA_GPIO_HP_DET,
+ .irq_base = AIC3262_CODEC_IRQ_BASE,
+};
+
static struct tegra_i2c_platform_data enterprise_i2c1_platform_data = {
.adapter_nr = 0,
.bus_count = 1,
@@ -237,7 +346,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 = { 400000, 0 },
+ .bus_clk_rate = { 390000, 0 },
.scl_gpio = {TEGRA_GPIO_PZ6, 0},
.sda_gpio = {TEGRA_GPIO_PZ7, 0},
.arb_recovery = arb_lost_recovery,
@@ -351,8 +460,9 @@ static struct i2c_board_info __initdata max98088_board_info = {
};
static struct i2c_board_info __initdata enterprise_codec_aic326x_info = {
- I2C_BOARD_INFO("aic3262-codec", 0x18),
- .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_HP_DET),
+ I2C_BOARD_INFO("tlv320aic3262", 0x18),
+ .platform_data = &aic3262_codec_pdata,
+ .irq = TEGRA_GPIO_HP_DET,
};
static struct i2c_board_info __initdata nfc_board_info = {
@@ -466,8 +576,6 @@ static void __init enterprise_uart_init(void)
ARRAY_SIZE(enterprise_uart_devices));
}
-
-
static struct resource tegra_rtc_resources[] = {
[0] = {
.start = TEGRA_RTC_BASE,
@@ -499,16 +607,26 @@ static struct tegra_asoc_platform_data enterprise_audio_pdata = {
.gpio_hp_mute = -1,
.gpio_int_mic_en = -1,
.gpio_ext_mic_en = -1,
- .debounce_time_hp = -1,
+ .debounce_time_hp = -1,
/*defaults for Enterprise board*/
- .audio_port_id = {
- [HIFI_CODEC] = 0,
- [BASEBAND] = 2,
- [BT_SCO] = 3,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 0,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ .sample_size = 16,
+ },
+ .i2s_param[BASEBAND] = {
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ .sample_size = 16,
+ .rate = 8000,
+ .channels = 1,
},
- .baseband_param = {
- .rate = 8000,
- .channels = 1,
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ .sample_size = 16,
},
};
@@ -527,15 +645,25 @@ static struct tegra_asoc_platform_data enterprise_audio_aic326x_pdata = {
.gpio_int_mic_en = -1,
.gpio_ext_mic_en = -1,
/*defaults for Verbier-Enterprise (E1197) board with TI AIC326X codec*/
- .audio_port_id = {
- [HIFI_CODEC] = 0,
- [BASEBAND] = 2,
- [BT_SCO] = 3,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ .sample_size = 16,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = 2,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ .sample_size = 16,
+ .rate = 8000,
+ .channels = 1,
},
- .baseband_param = {
- .rate = 8000,
- .channels = 1,
- .bit_format = TEGRA_DAIFMT_DSP_A,
+ .i2s_param[BT_SCO] = {
+ .sample_size = 16,
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
},
};
@@ -561,7 +689,6 @@ static struct platform_device *enterprise_devices[] __initdata = {
&tegra_avp_device,
#endif
&tegra_camera,
- &enterprise_bt_rfkill_device,
&tegra_spi_device4,
&tegra_hda_device,
#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
@@ -672,6 +799,14 @@ static void enterprise_usb_hsic_preresume(void)
#endif
}
+static void enterprise_usb_hsic_post_resume(void)
+{
+ pr_debug("%s\n", __func__);
+#ifdef CONFIG_TEGRA_BB_XMM_POWER
+ baseband_xmm_set_power_status(BBXMM_PS_L0);
+#endif
+}
+
static void enterprise_usb_hsic_phy_power(void)
{
pr_debug("%s\n", __func__);
@@ -692,6 +827,7 @@ 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_resume = enterprise_usb_hsic_post_resume,
.post_phy_off = enterprise_usb_hsic_post_phy_off,
};
@@ -706,21 +842,13 @@ static struct tegra_usb_platform_data tegra_ehci2_hsic_xmm_pdata = {
.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,
+ .builtin_host_disabled = true,
.phy_intf = TEGRA_USB_PHY_INTF_UTMI,
.op_mode = TEGRA_USB_OPMODE_DEVICE,
.u_data.dev = {
@@ -809,9 +937,15 @@ error:
return NULL;
}
-void tegra_usb_hsic_host_unregister(struct platform_device *pdev)
+void tegra_usb_hsic_host_unregister(struct platform_device **platdev)
{
- platform_device_unregister(pdev);
+ struct platform_device *pdev = *platdev;
+
+ if (pdev && &pdev->dev) {
+ platform_device_unregister(pdev);
+ *platdev = NULL;
+ } else
+ pr_err("%s: no platform device\n", __func__);
}
static void enterprise_usb_init(void)
@@ -829,7 +963,6 @@ static struct platform_device *enterprise_audio_devices[] __initdata = {
&tegra_dam_device2,
&tegra_i2s_device0,
&tegra_i2s_device1,
- &tegra_i2s_device2,
&tegra_i2s_device3,
&tegra_spdif_device,
&spdif_dit_device,
@@ -846,11 +979,31 @@ static void enterprise_audio_init(void)
tegra_get_board_info(&board_info);
- if (board_info.board_id == BOARD_E1197)
- enterprise_audio_pdata.audio_port_id[HIFI_CODEC] = 1;
+ if (board_info.board_id == BOARD_E1239) {
+ enterprise_audio_aic326x_pdata.i2s_param[BASEBAND].
+ audio_port_id = 4;
+ enterprise_audio_aic326x_pdata.i2s_param[BASEBAND].
+ i2s_mode = TEGRA_DAIFMT_I2S;
+ enterprise_audio_aic326x_pdata.i2s_param[BASEBAND].
+ channels = 2;
+ platform_device_register(&tegra_i2s_device4);
+ } else {
+ if (board_info.board_id == BOARD_E1197)
+ enterprise_audio_pdata.i2s_param[HIFI_CODEC].
+ audio_port_id = 1;
+ else if (board_info.fab == BOARD_FAB_A04) {
+ enterprise_audio_pdata.i2s_param[BASEBAND].
+ audio_port_id = 4;
+ platform_device_register(&tegra_i2s_device4);
+ } else {
+ enterprise_audio_pdata.i2s_param[BASEBAND].
+ audio_port_id = 2;
+ platform_device_register(&tegra_i2s_device2);
+ }
+ }
platform_add_devices(enterprise_audio_devices,
- ARRAY_SIZE(enterprise_audio_devices));
+ ARRAY_SIZE(enterprise_audio_devices));
}
@@ -917,8 +1070,12 @@ static struct platform_device tegra_baseband_m7400_device = {
static void enterprise_baseband_init(void)
{
+ struct board_info board_info;
+
int modem_id = tegra_get_modem_id();
+ tegra_get_board_info(&board_info);
+
switch (modem_id) {
case TEGRA_BB_PH450: /* PH450 ULPI */
enterprise_modem_init();
@@ -931,7 +1088,13 @@ static void enterprise_baseband_init(void)
&tegra_usb_hsic_host_register;
tegra_baseband_power_data.hsic_unregister =
&tegra_usb_hsic_host_unregister;
-
+ if ((board_info.board_id == BOARD_E1239) &&
+ (board_info.fab <= BOARD_FAB_A02)) {
+ tegra_baseband_power_data.modem.
+ xmm.ipc_hsic_active = BB_GPIO_LCD_PWR2;
+ tegra_baseband_power_data.modem.
+ xmm.ipc_hsic_sus_req = BB_GPIO_LCD_PWR1;
+ }
platform_device_register(&tegra_baseband_power_device);
platform_device_register(&tegra_baseband_power2_device);
break;
@@ -953,11 +1116,20 @@ static void enterprise_nfc_init(void)
tegra_get_board_info(&bi);
if (bi.board_id == BOARD_E1205 && bi.fab >= BOARD_FAB_A03) {
nfc_pdata.firm_gpio = TEGRA_GPIO_PX7;
+ } else if (bi.board_id == BOARD_E1239) {
+ nfc_pdata.firm_gpio = TEGRA_GPIO_PD2;
}
}
static void __init tegra_enterprise_init(void)
{
+ struct board_info board_info;
+ tegra_get_board_info(&board_info);
+ if (board_info.fab == BOARD_FAB_A04)
+ tegra_clk_init_from_table(enterprise_clk_i2s4_table);
+ else
+ tegra_clk_init_from_table(enterprise_clk_i2s2_table);
+
tegra_thermal_init(&thermal_data,
throttle_list,
ARRAY_SIZE(throttle_list));
@@ -966,9 +1138,12 @@ static void __init tegra_enterprise_init(void)
enterprise_i2c_init();
enterprise_uart_init();
enterprise_usb_init();
+ if (board_info.board_id == BOARD_E1239)
+ enterprise_bt_rfkill_pdata[0].reset_gpio = TEGRA_GPIO_PF4;
platform_add_devices(enterprise_devices, ARRAY_SIZE(enterprise_devices));
tegra_ram_console_debug_init();
enterprise_regulator_init();
+ tegra_io_dpd_init();
enterprise_sdhci_init();
#ifdef CONFIG_TEGRA_EDP_LIMITS
enterprise_edp_init();
@@ -979,6 +1154,10 @@ static void __init tegra_enterprise_init(void)
enterprise_audio_init();
enterprise_baseband_init();
enterprise_panel_init();
+ if (tegra_get_commchip_id() == COMMCHIP_TI_WL18XX)
+ enterprise_bt_st();
+ else
+ enterprise_bt_rfkill();
enterprise_setup_bluesleep();
enterprise_emc_init();
enterprise_sensors_init();
@@ -998,6 +1177,11 @@ static void __init tegra_enterprise_reserve(void)
tegra_ram_console_debug_reserve(SZ_1M);
}
+static const char *enterprise_dt_board_compat[] = {
+ "nvidia,enterprise",
+ NULL
+};
+
MACHINE_START(TEGRA_ENTERPRISE, "tegra_enterprise")
.boot_params = 0x80000100,
.map_io = tegra_map_common_io,
@@ -1006,4 +1190,5 @@ MACHINE_START(TEGRA_ENTERPRISE, "tegra_enterprise")
.init_irq = tegra_init_irq,
.timer = &tegra_timer,
.init_machine = tegra_enterprise_init,
+ .dt_compat = enterprise_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-tegra/board-enterprise.h b/arch/arm/mach-tegra/board-enterprise.h
index 3c6d149abdff..ae488dfb4618 100644
--- a/arch/arm/mach-tegra/board-enterprise.h
+++ b/arch/arm/mach-tegra/board-enterprise.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/board-enterprise.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
@@ -28,6 +28,7 @@
/* Processor Board ID */
#define BOARD_E1205 0x0C05
#define BOARD_E1197 0x0B61
+#define BOARD_E1239 0x0C27
#define SKU_BATTERY_SUPPORT 0x1
/* Board Fab version */
@@ -93,6 +94,11 @@ void enterprise_bpc_mgmt_init(void);
#define ENT_TPS80031_IRQ_BASE TEGRA_NR_IRQS
#define ENT_TPS80031_IRQ_END (ENT_TPS80031_IRQ_BASE + TPS80031_INT_NR)
+/* AIC326X IRQs */
+/* Assuming TPS is the PMIC on Ent */
+#define AIC3262_CODEC_IRQ_BASE ENT_TPS80031_IRQ_END
+#define AIC3262_CODEC_IRQ_END (AIC3262_CODEC_IRQ_BASE + 6)
+
/*****************Camera GPIOs ******************/
#define CAM_CSI_MUX_SEL_GPIO TEGRA_GPIO_PM3
#define CAM_CSI_MUX_SEL_REAR 1
@@ -113,7 +119,10 @@ void enterprise_bpc_mgmt_init(void);
/* Audio-related GPIOs */
#define TEGRA_GPIO_HP_DET TEGRA_GPIO_PW3
+#define TEGRA_GPIO_CODEC_RST TEGRA_GPIO_PX0
+/* UART port which is used by bluetooth*/
+#define BLUETOOTH_UART_DEV_NAME "/dev/ttyHS2"
/* Baseband GPIO addresses */
#define GPIO_BB_RESET TEGRA_GPIO_PE1
@@ -159,6 +168,7 @@ enum tegra_bb_type {
};
/* Indicate the pwm of backlight, DC pwm or external pwm3. */
+/* External pwm is used for TAI (E1239) but do not set this compiler switch */
#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 d4cd3f461b66..ff1c44ad0f3a 100644
--- a/arch/arm/mach-tegra/board-harmony-panel.c
+++ b/arch/arm/mach-tegra/board-harmony-panel.c
@@ -57,8 +57,6 @@ static int harmony_backlight_init(struct device *dev)
ret = gpio_direction_output(harmony_bl_enb, 1);
if (ret < 0)
gpio_free(harmony_bl_enb);
- else
- tegra_gpio_enable(harmony_bl_enb);
return ret;
}
@@ -67,7 +65,6 @@ static void harmony_backlight_exit(struct device *dev)
{
gpio_set_value(harmony_bl_enb, 0);
gpio_free(harmony_bl_enb);
- tegra_gpio_disable(harmony_bl_enb);
}
static int harmony_backlight_notify(struct device *unused, int brightness)
@@ -337,19 +334,15 @@ int __init harmony_panel_init(void)
gpio_request(harmony_en_vdd_pnl, "en_vdd_pnl");
gpio_direction_output(harmony_en_vdd_pnl, 1);
- tegra_gpio_enable(harmony_en_vdd_pnl);
gpio_request(harmony_bl_vdd, "bl_vdd");
gpio_direction_output(harmony_bl_vdd, 1);
- tegra_gpio_enable(harmony_bl_vdd);
gpio_request(harmony_lvds_shutdown, "lvds_shdn");
gpio_direction_output(harmony_lvds_shutdown, 1);
- tegra_gpio_enable(harmony_lvds_shutdown);
gpio_request(harmony_hdmi_hpd, "hdmi_hpd");
gpio_direction_input(harmony_hdmi_hpd);
- tegra_gpio_enable(harmony_hdmi_hpd);
#if defined(CONFIG_TEGRA_NVMAP)
harmony_carveouts[1].base = tegra_carveout_start;
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index dd14435cc17c..0e8a9f18c6d9 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2010 Google, Inc.
* Copyright (C) 2011 NVIDIA, 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
@@ -43,7 +44,7 @@
#include <asm/mach/time.h>
#include <asm/setup.h>
-#include <mach/tegra_wm8903_pdata.h>
+#include <mach/tegra_asoc_pdata.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
#include <mach/sdhci.h>
@@ -222,20 +223,25 @@ static struct platform_device harmony_gpio_keys_device = {
}
};
-static void harmony_keys_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(harmony_gpio_keys_buttons); i++)
- tegra_gpio_enable(harmony_gpio_keys_buttons[i].gpio);
-}
-
-static struct tegra_wm8903_platform_data harmony_audio_pdata = {
+static struct tegra_asoc_platform_data harmony_audio_pdata = {
.gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
.gpio_hp_det = TEGRA_GPIO_HP_DET,
.gpio_hp_mute = -1,
.gpio_int_mic_en = TEGRA_GPIO_INT_MIC_EN,
.gpio_ext_mic_en = TEGRA_GPIO_EXT_MIC_EN,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ },
};
static struct platform_device harmony_audio_device = {
@@ -486,8 +492,6 @@ static int __init harmony_wifi_prepower(void)
pr_warning("Unable to get gpio for WLAN Power and Reset\n");
else {
- tegra_gpio_enable(TEGRA_GPIO_WLAN_PWR_LOW);
- tegra_gpio_enable(TEGRA_GPIO_WLAN_RST_LOW);
/* toggle in this order as per spec */
gpio_direction_output(TEGRA_GPIO_WLAN_PWR_LOW, 0);
gpio_direction_output(TEGRA_GPIO_WLAN_RST_LOW, 0);
@@ -514,8 +518,6 @@ static void __init tegra_harmony_init(void)
harmony_pinmux_init();
- harmony_keys_init();
-
harmony_uart_init();
tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
diff --git a/arch/arm/mach-tegra/board-kai-memory.c b/arch/arm/mach-tegra/board-kai-memory.c
index 1f812ece741b..07d6405c7016 100644
--- a/arch/arm/mach-tegra/board-kai-memory.c
+++ b/arch/arm/mach-tegra/board-kai-memory.c
@@ -117,8 +117,8 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000287, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00020001, /* MC_EMEM_ARB_CFG */
- 0xc0000008, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00030003, /* 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 */
@@ -237,8 +237,8 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x8000040b, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00010001, /* MC_EMEM_ARB_CFG */
- 0xc000000a, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00010003, /* 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 */
@@ -357,8 +357,8 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000713, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000001, /* MC_EMEM_ARB_CFG */
- 0xc0000013, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0xc0000018, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
0x00000003, /* MC_EMEM_ARB_TIMING_RC */
@@ -477,7 +477,7 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x80000d22, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000003, /* MC_EMEM_ARB_CFG */
+ 0x00000006, /* MC_EMEM_ARB_CFG */
0xc0000025, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000001, /* MC_EMEM_ARB_TIMING_RP */
@@ -597,8 +597,8 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800014d4, /* EMC_DYN_SELF_REF_CONTROL */
- 0x00000005, /* MC_EMEM_ARB_CFG */
- 0x8000003d, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x0000000a, /* MC_EMEM_ARB_CFG */
+ 0xc000003d, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000001, /* MC_EMEM_ARB_TIMING_RCD */
0x00000002, /* MC_EMEM_ARB_TIMING_RP */
0x00000008, /* MC_EMEM_ARB_TIMING_RC */
@@ -717,8 +717,8 @@ static const struct tegra_emc_table kai_emc_tables_h5tc4g[] = {
0x00000000, /* EMC_CTT */
0x00000000, /* EMC_CTT_DURATION */
0x800028a5, /* EMC_DYN_SELF_REF_CONTROL */
- 0x0000000a, /* MC_EMEM_ARB_CFG */
- 0x80000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
+ 0x00000014, /* MC_EMEM_ARB_CFG */
+ 0xc0000079, /* MC_EMEM_ARB_OUTSTANDING_REQ */
0x00000003, /* MC_EMEM_ARB_TIMING_RCD */
0x00000004, /* MC_EMEM_ARB_TIMING_RP */
0x00000010, /* MC_EMEM_ARB_TIMING_RC */
diff --git a/arch/arm/mach-tegra/board-kai-power.c b/arch/arm/mach-tegra/board-kai-power.c
index 6c66f1d2bbe9..027d97458dd3 100644
--- a/arch/arm/mach-tegra/board-kai-power.c
+++ b/arch/arm/mach-tegra/board-kai-power.c
@@ -614,6 +614,14 @@ static struct tegra_suspend_platform_data kai_suspend_data = {
.cpu_lp2_min_residency = 2000,
.board_suspend = kai_board_suspend,
.board_resume = kai_board_resume,
+#ifdef CONFIG_TEGRA_LP1_950
+ .lp1_lowvolt_support = true,
+ .i2c_base_addr = TEGRA_I2C5_BASE,
+ .pmuslave_addr = 0x78,
+ .core_reg_addr = 0x17,
+ .lp1_core_volt_low = 0x0C,
+ .lp1_core_volt_high = 0x20,
+#endif
};
int __init kai_suspend_init(void)
diff --git a/arch/arm/mach-tegra/board-kai-sdhci.c b/arch/arm/mach-tegra/board-kai-sdhci.c
index 0fa39ccf475d..70ba7bcdb202 100644
--- a/arch/arm/mach-tegra/board-kai-sdhci.c
+++ b/arch/arm/mach-tegra/board-kai-sdhci.c
@@ -28,6 +28,7 @@
#include <mach/irqs.h>
#include <mach/iomap.h>
#include <mach/sdhci.h>
+#include <mach/io_dpd.h>
#include "gpio-names.h"
#include "board.h"
@@ -202,8 +203,21 @@ static int kai_wifi_set_carddetect(int val)
static int kai_wifi_power(int power_on)
{
+ struct tegra_io_dpd *sd_dpd;
pr_err("Powering %s wifi\n", (power_on ? "on" : "off"));
+ /*
+ * FIXME : we need to revisit IO DPD code
+ * on how should multiple pins under DPD get controlled
+ *
+ * kai GPIO WLAN enable is part of SDMMC3 pin group
+ */
+ sd_dpd = tegra_io_dpd_get(&tegra_sdhci_device2.dev);
+ if (sd_dpd) {
+ mutex_lock(&sd_dpd->delay_lock);
+ tegra_io_dpd_disable(sd_dpd);
+ mutex_unlock(&sd_dpd->delay_lock);
+ }
if (power_on) {
gpio_set_value(KAI_WLAN_EN, 1);
mdelay(15);
@@ -214,6 +228,11 @@ static int kai_wifi_power(int power_on)
} else {
gpio_set_value(KAI_WLAN_EN, 0);
}
+ if (sd_dpd) {
+ mutex_lock(&sd_dpd->delay_lock);
+ tegra_io_dpd_enable(sd_dpd);
+ mutex_unlock(&sd_dpd->delay_lock);
+ }
return 0;
}
diff --git a/arch/arm/mach-tegra/board-kai-sensors.c b/arch/arm/mach-tegra/board-kai-sensors.c
index 29d1bea2e8a7..048c39c9759f 100644
--- a/arch/arm/mach-tegra/board-kai-sensors.c
+++ b/arch/arm/mach-tegra/board-kai-sensors.c
@@ -179,8 +179,15 @@ static int kai_camera_init(void)
static int kai_ov2710_power_on(void)
{
- gpio_direction_output(CAM2_POWER_DWN_GPIO, 0);
- mdelay(10);
+ if (kai_1v8_cam3 == NULL) {
+ kai_1v8_cam3 = regulator_get(NULL, "vdd_1v8_cam3");
+ if (WARN_ON(IS_ERR(kai_1v8_cam3))) {
+ pr_err("%s: couldn't get regulator vdd_1v8_cam3: %d\n",
+ __func__, (int)PTR_ERR(kai_1v8_cam3));
+ goto reg_get_vdd_1v8_cam3_fail;
+ }
+ }
+ regulator_enable(kai_1v8_cam3);
if (kai_vdd_cam3 == NULL) {
kai_vdd_cam3 = regulator_get(NULL, "vdd_cam3");
@@ -191,43 +198,36 @@ static int kai_ov2710_power_on(void)
}
}
regulator_enable(kai_vdd_cam3);
-
- if (kai_1v8_cam3 == NULL) {
- kai_1v8_cam3 = regulator_get(NULL, "vdd_1v8_cam3");
- if (WARN_ON(IS_ERR(kai_1v8_cam3))) {
- pr_err("%s: couldn't get regulator vdd_1v8_cam3: %d\n",
- __func__, (int)PTR_ERR(kai_1v8_cam3));
- goto reg_get_vdd_1v8_cam3_fail;
- }
- }
- regulator_enable(kai_1v8_cam3);
mdelay(5);
+ gpio_direction_output(CAM2_POWER_DWN_GPIO, 0);
+ mdelay(10);
+
gpio_direction_output(CAM2_RST_GPIO, 1);
mdelay(10);
return 0;
-reg_get_vdd_1v8_cam3_fail:
- kai_1v8_cam3 = NULL;
- regulator_put(kai_vdd_cam3);
-
reg_get_vdd_cam3_fail:
kai_vdd_cam3 = NULL;
+ regulator_put(kai_1v8_cam3);
+
+reg_get_vdd_1v8_cam3_fail:
+ kai_1v8_cam3 = NULL;
return -ENODEV;
}
static int kai_ov2710_power_off(void)
{
- gpio_direction_output(CAM2_POWER_DWN_GPIO, 1);
-
gpio_direction_output(CAM2_RST_GPIO, 0);
- if (kai_1v8_cam3)
- regulator_disable(kai_1v8_cam3);
+ gpio_direction_output(CAM2_POWER_DWN_GPIO, 1);
+
if (kai_vdd_cam3)
regulator_disable(kai_vdd_cam3);
+ if (kai_1v8_cam3)
+ regulator_disable(kai_1v8_cam3);
return 0;
}
diff --git a/arch/arm/mach-tegra/board-kai.c b/arch/arm/mach-tegra/board-kai.c
index bf4ae415072d..83874f89d836 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. All rights reserved.
+ * 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
@@ -50,8 +50,9 @@
#include <mach/pinmux.h>
#include <mach/iomap.h>
#include <mach/io.h>
+#include <mach/io_dpd.h>
#include <mach/i2s.h>
-#include <mach/tegra_rt5640_pdata.h>
+#include <mach/tegra_asoc_pdata.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/usb_phy.h>
@@ -574,12 +575,25 @@ static struct platform_device tegra_rtc_device = {
.num_resources = ARRAY_SIZE(tegra_rtc_resources),
};
-static struct tegra_rt5640_platform_data kai_audio_pdata = {
+static struct tegra_asoc_platform_data kai_audio_pdata = {
.gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
.gpio_hp_det = TEGRA_GPIO_HP_DET,
.gpio_hp_mute = -1,
.gpio_int_mic_en = TEGRA_GPIO_INT_MIC_EN,
.gpio_ext_mic_en = TEGRA_GPIO_EXT_MIC_EN,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ },
};
static struct platform_device kai_audio_device = {
@@ -870,6 +884,7 @@ static void __init tegra_kai_init(void)
kai_audio_init();
platform_add_devices(kai_devices, ARRAY_SIZE(kai_devices));
tegra_ram_console_debug_init();
+ tegra_io_dpd_init();
kai_sdhci_init();
kai_regulator_init();
kai_suspend_init();
diff --git a/arch/arm/mach-tegra/board-p1852-panel.c b/arch/arm/mach-tegra/board-p1852-panel.c
index 4e86476cdd2c..8ca533175ea1 100644
--- a/arch/arm/mach-tegra/board-p1852-panel.c
+++ b/arch/arm/mach-tegra/board-p1852-panel.c
@@ -29,7 +29,27 @@
#include "board.h"
#include "devices.h"
#include "tegra3_host1x_devices.h"
+#include "board-p1852.h"
+#include "gpio-names.h"
+#define P1852_LVDS_ENA1 TEGRA_GPIO_PV0
+#define P1852_LVDS_ENA2 TEGRA_GPIO_PV1
+#define P1852_HDMI_HPD TEGRA_GPIO_PN7
+#define P1852_HDMI_RGB TEGRA_GPIO_PW1
+#define P1852_LVDS_SER1_ADDR 0xd
+#define P1852_LVDS_SER2_ADDR 0xc
+
+#define LVDS_SER_REG_CONFIG_1 0x4
+#define LVDS_SER_REG_CONFIG_1_BKWD_OVERRIDE 3
+#define LVDS_SER_REG_CONFIG_1_BKWD 2
+
+#define LVDS_SER_REG_DATA_PATH_CTRL 0x12
+#define LVDS_SER_REG_DATA_PATH_CTRL_PASS_RGB 6
+
+#define LVDS_SER_REG_CONFIG_0 0x3
+#define LVDS_SER_REG_CONFIG_0_TRFB 0
+
+/* RGB panel requires no special enable/disable */
static int p1852_panel_enable(void)
{
return 0;
@@ -40,6 +60,199 @@ static int p1852_panel_disable(void)
return 0;
}
+static int ser_i2c_read(struct i2c_client *client,
+ u8 reg_addr, u8 *pval)
+{
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg_addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = pval,
+ },
+ };
+
+ return i2c_transfer(client->adapter, msg, 2);
+}
+
+static int ser_i2c_write(struct i2c_client *client,
+ u8 reg_addr, u8 val)
+{
+ u8 buffer[] = {reg_addr, val};
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buffer,
+ },
+ };
+
+ return i2c_transfer(client->adapter, msg, 1);
+}
+
+static int lvds_ser_init(struct i2c_client *client,
+ bool is_fpdlinkII,
+ bool support_hdcp,
+ bool clk_rise_edge)
+{
+ u8 val;
+ int err = 0;
+
+ /* intentional call make register & bus ready */
+ ser_i2c_read(client, LVDS_SER_REG_CONFIG_1, &val);
+
+ if (is_fpdlinkII) {
+ err = ser_i2c_read(client, LVDS_SER_REG_CONFIG_1, &val);
+ if (err < 0)
+ return err;
+
+ val |= (1 << LVDS_SER_REG_CONFIG_1_BKWD_OVERRIDE);
+ val |= (1 << LVDS_SER_REG_CONFIG_1_BKWD);
+
+ err = ser_i2c_write(client, LVDS_SER_REG_CONFIG_1, val);
+ if (err < 0)
+ return err;
+ }
+ else if (!support_hdcp) {
+ err = ser_i2c_read(client, LVDS_SER_REG_DATA_PATH_CTRL, &val);
+ if (err < 0)
+ return err;
+
+ val |= (1 << LVDS_SER_REG_DATA_PATH_CTRL_PASS_RGB);
+
+ err = ser_i2c_write(client, LVDS_SER_REG_DATA_PATH_CTRL, val);
+ if (err < 0)
+ return err;
+ }
+
+ if (clk_rise_edge) {
+ err = ser_i2c_read(client, LVDS_SER_REG_CONFIG_0, &val);
+ if (err < 0)
+ return err;
+
+ val |= (1 << LVDS_SER_REG_CONFIG_0_TRFB);
+
+ err = ser_i2c_write(client, LVDS_SER_REG_CONFIG_0, val);
+ }
+
+ return (err < 0 ? err : 0);
+}
+
+/* enable primary LVDS */
+static int p1852_lvds_enable(void)
+{
+ struct i2c_adapter *adapter;
+ struct i2c_board_info info = {{0}};
+ static struct i2c_client *client;
+ int err = -1;
+
+ /* Turn on serializer chip */
+ gpio_set_value(P1852_LVDS_ENA1, 1);
+
+ /* Program the serializer */
+ adapter = i2c_get_adapter(3);
+ if (!adapter)
+ pr_warning("%s: adapter is null\n", __func__);
+ else {
+ info.addr = P1852_LVDS_SER1_ADDR;
+ if (!client)
+ client = i2c_new_device(adapter, &info);
+ i2c_put_adapter(adapter);
+ if (!client)
+ pr_warning("%s: client is null\n", __func__);
+ else {
+ err = lvds_ser_init(client,
+ true, /* is_fpdlinkII*/
+ false, /* support_hdcp */
+ true); /* clk_rise_edge */
+ }
+ }
+ return err;
+}
+
+/* Disable primary LVDS */
+static int p1852_lvds_disable(void)
+{
+ /* Turn off serializer chip */
+ gpio_set_value(P1852_LVDS_ENA1, 0);
+
+ return 0;
+}
+
+/* Enable secondary LVDS */
+static int p1852_lvds2_enable(void)
+{
+ struct i2c_adapter *adapter;
+ struct i2c_board_info info = {{0}};
+ static struct i2c_client *client;
+ int err = -1;
+
+ /* Enable HDMI HPD */
+ /* need nothing here */
+
+ /* Turn on HDMI-RGB converter */
+ gpio_set_value(P1852_HDMI_RGB, 1);
+
+ /* Turn on serializer chip */
+ gpio_set_value(P1852_LVDS_ENA2, 1);
+
+ /* Program the serializer */
+ adapter = i2c_get_adapter(3);
+ if (!adapter)
+ pr_warning("%s: adapter is null\n", __func__);
+ else {
+ info.addr = P1852_LVDS_SER2_ADDR;
+ if (!client)
+ client = i2c_new_device(adapter, &info);
+ i2c_put_adapter(adapter);
+ if (!client)
+ pr_warning("%s: client is null\n", __func__);
+ else {
+ err = lvds_ser_init(client,
+ true, /* is_fpdlinkII*/
+ false, /* support_hdcp */
+ true); /* clk_rise_edge */
+ }
+ }
+ return err;
+}
+
+/* Disable secondary LVDS */
+static int p1852_lvds2_disable(void)
+{
+ /* Turn off serializer chip */
+ gpio_set_value(P1852_LVDS_ENA2, 0);
+
+ /* Turn off HDMI-RGB converter */
+ gpio_set_value(P1852_HDMI_RGB, 0);
+
+ /* Turn off HDMI */
+ /* need nothing here */
+
+ return 0;
+}
+
+/* Enable secondary HDMI */
+static int p1852_hdmi_enable(void)
+{
+ /* need nothing here */
+ return 0;
+}
+
+/* Disable secondary HDMI */
+static int p1852_hdmi_disable(void)
+{
+ /* need nothing here */
+ return 0;
+}
+
#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT
static struct tegra_dc_mode p1852_panel_modes[] = {
@@ -123,9 +336,42 @@ static struct tegra_fb_data p1852_fb_data = {
#endif
+/* Mode data for secondary LVDS out */
+static struct tegra_dc_mode p1852_hdmi_lvds_modes[] = {
+ {
+ /* 800x480@60 */
+ .pclk = 33260000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 64,
+ .v_sync_width = 3,
+ .h_back_porch = 128,
+ .v_back_porch = 38,
+ .h_front_porch = 64,
+ .v_front_porch = 4,
+ .h_active = 800,
+ .v_active = 480,
+ },
+};
+
+static struct tegra_fb_data p1852_hdmi_fb_data = {
+ .win = 0,
+ .xres = 800,
+ .yres = 480,
+ .bits_per_pixel = 32,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+/* Start of DC_OUT data
+ * disp1 = Primary RGB out
+ * ser1 = Primary LVDS out
+ * ser2 = Secondary LVDS out
+ * hdmi = Secondary HDMI out
+ */
static struct tegra_dc_out p1852_disp1_out = {
.align = TEGRA_DC_ALIGN_MSB,
.order = TEGRA_DC_ORDER_RED_BLUE,
+ .parent_clk = "pll_d_out0",
.type = TEGRA_DC_OUT_RGB,
.modes = p1852_panel_modes,
.n_modes = ARRAY_SIZE(p1852_panel_modes),
@@ -133,6 +379,51 @@ static struct tegra_dc_out p1852_disp1_out = {
.disable = p1852_panel_disable,
};
+static struct tegra_dc_out p1852_ser1_out = {
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .parent_clk = "pll_d_out0",
+ .type = TEGRA_DC_OUT_RGB,
+ .modes = p1852_panel_modes,
+ .n_modes = ARRAY_SIZE(p1852_panel_modes),
+ .enable = p1852_lvds_enable,
+ .disable = p1852_lvds_disable,
+};
+
+static struct tegra_dc_out p1852_ser2_out = {
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .parent_clk = "pll_d2_out0",
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_LOW |
+ TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND,
+ .max_pixclock = KHZ2PICOS(148500),
+ .hotplug_gpio = P1852_HDMI_HPD,
+ .modes = p1852_hdmi_lvds_modes,
+ .n_modes = ARRAY_SIZE(p1852_hdmi_lvds_modes),
+ .enable = p1852_lvds2_enable,
+ .disable = p1852_lvds2_disable,
+ .dcc_bus = 3,
+};
+
+static struct tegra_dc_out p1852_hdmi_out = {
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .parent_clk = "pll_d2_out0",
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_LOW |
+ TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND,
+ .max_pixclock = KHZ2PICOS(148500),
+ .hotplug_gpio = P1852_HDMI_HPD,
+ .enable = p1852_hdmi_enable,
+ .disable = p1852_hdmi_disable,
+
+ .dcc_bus = 1,
+};
+
+/* End of DC_OUT data */
+
+/* Start of platform data */
static struct tegra_dc_platform_data p1852_disp1_pdata = {
.flags = TEGRA_DC_FLAG_ENABLED,
.default_out = &p1852_disp1_out,
@@ -140,6 +431,29 @@ static struct tegra_dc_platform_data p1852_disp1_pdata = {
.fb = &p1852_fb_data,
};
+static struct tegra_dc_platform_data p1852_ser1_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &p1852_ser1_out,
+ .emc_clk_rate = 300000000,
+ .fb = &p1852_fb_data,
+};
+
+static struct tegra_dc_platform_data p1852_ser2_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &p1852_ser2_out,
+ .emc_clk_rate = 300000000,
+ .fb = &p1852_hdmi_fb_data,
+};
+
+static struct tegra_dc_platform_data p1852_hdmi_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &p1852_hdmi_out,
+ .emc_clk_rate = 300000000,
+ .fb = &p1852_hdmi_fb_data,
+};
+
+/* End of platform data */
+
static struct nvmap_platform_carveout p1852_carveouts[] = {
[0] = {
.name = "iram",
@@ -166,7 +480,7 @@ static struct platform_device *p1852_gfx_devices[] __initdata = {
&tegra_nvmap_device,
};
-int __init p1852_panel_init(void)
+static int __init p1852_sku2_panel_init(void)
{
int err;
struct resource *res;
@@ -174,16 +488,62 @@ int __init p1852_panel_init(void)
p1852_carveouts[1].base = tegra_carveout_start;
p1852_carveouts[1].size = tegra_carveout_size;
tegra_nvmap_device.dev.platform_data = &p1852_nvmap_data;
- tegra_disp1_device.dev.platform_data = &p1852_disp1_pdata;
+ /*
+ * sku2 has primary LVDS out and secondary LVDS out
+ * (via HDMI->RGB->Serializer)
+ */
+ tegra_disp1_device.dev.platform_data = &p1852_ser1_pdata;
+ tegra_disp2_device.dev.platform_data = &p1852_ser2_pdata;
+#ifdef CONFIG_TEGRA_GRHOST
+ err = tegra3_register_host1x_devices();
+ if (err)
+ return err;
+#endif
+
+ err = platform_add_devices(p1852_gfx_devices,
+ ARRAY_SIZE(p1852_gfx_devices));
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
res = nvhost_get_resource_byname(&tegra_disp1_device,
IORESOURCE_MEM, "fbmem");
- if (!res) {
- pr_err("No memory resources\n");
- return -ENODEV;
+ if (res) {
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+ }
+
+ if (!err)
+ err = nvhost_device_register(&tegra_disp1_device);
+
+ res = nvhost_get_resource_byname(&tegra_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ if (res) {
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
}
- res->start = tegra_fb_start;
- res->end = tegra_fb_start + tegra_fb_size - 1;
+
+ if (!err)
+ err = nvhost_device_register(&tegra_disp2_device);
+#endif
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP)
+ if (!err)
+ err = nvhost_device_register(&nvavp_device);
+#endif
+ return err;
+}
+
+static int __init p1852_sku8_panel_init(void)
+{
+ int err;
+ struct resource *res;
+
+ p1852_carveouts[1].base = tegra_carveout_start;
+ p1852_carveouts[1].size = tegra_carveout_size;
+ tegra_nvmap_device.dev.platform_data = &p1852_nvmap_data;
+ /* sku 8 has primary RGB out and secondary HDMI out */
+ tegra_disp1_device.dev.platform_data = &p1852_disp1_pdata;
+ tegra_disp2_device.dev.platform_data = &p1852_hdmi_pdata;
#ifdef CONFIG_TEGRA_GRHOST
err = tegra3_register_host1x_devices();
@@ -193,12 +553,50 @@ int __init p1852_panel_init(void)
err = platform_add_devices(p1852_gfx_devices,
ARRAY_SIZE(p1852_gfx_devices));
+
+#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_DC)
+ res = nvhost_get_resource_byname(&tegra_disp1_device,
+ IORESOURCE_MEM, "fbmem");
+ if (res) {
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+ }
+
if (!err)
err = nvhost_device_register(&tegra_disp1_device);
+ res = nvhost_get_resource_byname(&tegra_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ if (res) {
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
+ }
+
+ if (!err)
+ err = nvhost_device_register(&tegra_disp2_device);
+#endif
+
#if defined(CONFIG_TEGRA_GRHOST) && defined(CONFIG_TEGRA_NVAVP)
if (!err)
err = nvhost_device_register(&nvavp_device);
#endif
return err;
}
+
+int __init p1852_panel_init(void)
+{
+ int skuid;
+
+ skuid = p1852_get_skuid();
+
+ switch (skuid) {
+ case 2:
+ return p1852_sku2_panel_init();
+ case 5: /* Sku 5 display is same as 8 */
+ case 8:
+ return p1852_sku8_panel_init();
+ default:
+ pr_warning("%s: unknown skuid %d\n", __func__, skuid);
+ return 1;
+ }
+}
diff --git a/arch/arm/mach-tegra/board-p1852-pinmux.c b/arch/arm/mach-tegra/board-p1852-pinmux.c
index 21f310b0ef16..bb28e278dc89 100644
--- a/arch/arm/mach-tegra/board-p1852-pinmux.c
+++ b/arch/arm/mach-tegra/board-p1852-pinmux.c
@@ -119,13 +119,8 @@ static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = {
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),
@@ -184,6 +179,9 @@ static __initdata struct tegra_drive_pingroup_config p1852_drive_pinmux[] = {
}
+static __initdata struct tegra_pingroup_config p1852_pinmux_i2s4_master[] = {
+ DEFAULT_PINMUX(SDMMC4_CLK, NAND, PULL_UP, NORMAL, INPUT),
+};
static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
/* SDMMC1 pinmux */
@@ -291,10 +289,10 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
DEFAULT_PINMUX(DAP3_SCLK, I2S2, NORMAL, NORMAL, INPUT),
/* DAP3 */
- 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),
+ 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),
/* NOR pinmux */
DEFAULT_PINMUX(GMI_AD0, GMI, NORMAL, NORMAL, INPUT),
@@ -427,7 +425,7 @@ static __initdata struct tegra_pingroup_config p1852_pinmux_common[] = {
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(SDMMC4_CLK, NAND, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC3_DAT3, RSVD0, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(VI_D1, RSVD1, NORMAL, NORMAL, INPUT),
@@ -445,6 +443,12 @@ int __init p1852_pinmux_init(void)
return 0;
}
+int p1852_pinmux_set_i2s4_master(void)
+{
+ tegra_pinmux_config_table(p1852_pinmux_i2s4_master,
+ ARRAY_SIZE(p1852_pinmux_i2s4_master));
+ return 0;
+}
#define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \
{ \
.gpio_nr = _gpio, \
diff --git a/arch/arm/mach-tegra/board-p1852.c b/arch/arm/mach-tegra/board-p1852.c
index ce7768e19594..4ff3eaf47899 100644
--- a/arch/arm/mach-tegra/board-p1852.c
+++ b/arch/arm/mach-tegra/board-p1852.c
@@ -1,6 +1,4 @@
/*
- * arch/arm/mach-tegra/board-p1852.c
- *
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
@@ -15,6 +13,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
+ * arch/arm/mach-tegra/board-p1852.c
+ *
*/
#include <linux/kernel.h>
@@ -43,6 +43,7 @@
#include <mach/irqs.h>
#include <mach/pinmux.h>
#include <mach/iomap.h>
+#include <mach/io_dpd.h>
#include <mach/io.h>
#include <mach/pci.h>
#include <mach/audio.h>
@@ -96,7 +97,6 @@ static __initdata struct tegra_clk_init_table p1852_clk_init_table[] = {
{ "vi", "pll_p", 470000000, false},
{ "vi_sensor", "pll_p", 150000000, false},
{ "vde", "pll_c", 484000000, true},
- { "host1x", "pll_c", 242000000, true},
{ "mpe", "pll_c", 484000000, true},
{ "se", "pll_m", 625000000, true},
{ "i2c1", "pll_p", 3200000, true},
@@ -198,7 +198,6 @@ static void __init p1852_uart_init(void)
platform_add_devices(p1852_uart_devices,
ARRAY_SIZE(p1852_uart_devices));
}
-
#if defined(CONFIG_TEGRA_P1852_TDM)
static struct tegra_p1852_platform_data p1852_audio_tdm_pdata = {
.codec_info[0] = {
@@ -208,11 +207,15 @@ static struct tegra_p1852_platform_data p1852_audio_tdm_pdata = {
.name = "tegra-i2s-1",
.pcm_driver = "tegra-tdm-pcm-audio",
.i2s_format = format_tdm,
+ /* Defines whether the Codec Chip is Master or Slave */
.master = 1,
- .num_slots = 4,
+ /* Defines the number of TDM slots */
+ .num_slots = 8,
+ /* Defines the width of each slot */
.slot_width = 32,
- .tx_mask = 0x0f,
- .rx_mask = 0x0f,
+ /* Defines which slots are enabled */
+ .tx_mask = 0xff,
+ .rx_mask = 0xff,
},
.codec_info[1] = {
.codec_dai_name = "dit-hifi",
@@ -237,6 +240,7 @@ static struct tegra_p1852_platform_data p1852_audio_i2s_pdata = {
.name = "tegra-i2s-1",
.pcm_driver = "tegra-pcm-audio",
.i2s_format = format_i2s,
+ /* Defines whether the Audio codec chip is master or slave */
.master = 1,
},
.codec_info[1] = {
@@ -246,6 +250,7 @@ static struct tegra_p1852_platform_data p1852_audio_i2s_pdata = {
.name = "tegra-i2s-2",
.pcm_driver = "tegra-pcm-audio",
.i2s_format = format_i2s,
+ /* Defines whether the Audio codec chip is master or slave */
.master = 0,
},
};
@@ -273,6 +278,8 @@ static struct platform_device tegra_snd_p1852 = {
static void p1852_i2s_audio_init(void)
{
+ struct tegra_p1852_platform_data *pdata;
+
platform_device_register(&tegra_pcm_device);
platform_device_register(&tegra_tdm_pcm_device);
platform_device_register(&generic_codec_1);
@@ -281,6 +288,11 @@ static void p1852_i2s_audio_init(void)
platform_device_register(&tegra_i2s_device4);
platform_device_register(&tegra_ahub_device);
platform_device_register(&tegra_snd_p1852);
+
+ /* Change pinmux of I2S4 for master mode */
+ pdata = tegra_snd_p1852.dev.platform_data;
+ if (!pdata->codec_info[1].master)
+ p1852_pinmux_set_i2s4_master();
}
@@ -445,9 +457,6 @@ static __initdata struct tegra_clk_init_table spi_clk_init_table[] = {
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);
@@ -467,6 +476,32 @@ static int __init p1852_touch_init(void)
#endif // CONFIG_TOUCHSCREEN_ATMEL_MXT
+#if defined(CONFIG_USB_G_ANDROID)
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+ .port_otg = false,
+ .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,
+ .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,
+ },
+};
+#else
static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
.port_otg = false,
.has_hostpc = true,
@@ -492,6 +527,7 @@ static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
.xcvr_use_lsb = 1,
},
};
+#endif
static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
.port_otg = false,
@@ -547,9 +583,16 @@ static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
static void p1852_usb_init(void)
{
+ /* Need to parse sku info to decide host/device mode */
+
+ /* G_ANDROID require device mode */
+#if defined(CONFIG_USB_G_ANDROID)
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+ platform_device_register(&tegra_udc_device);
+#else
tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata;
platform_device_register(&tegra_ehci1_device);
-
+#endif
tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
platform_device_register(&tegra_ehci2_device);
@@ -563,6 +606,10 @@ static struct tegra_nor_platform_data p1852_nor_data = {
.width = 2,
},
.chip_parms = {
+ .MuxMode = NorMuxMode_ADNonMux,
+ .ReadMode = NorReadMode_Page,
+ .PageLength = NorPageLength_8Word,
+ .ReadyActive = NorReadyActive_WithData,
/* FIXME: Need to use characterized value */
.timing_default = {
.timing0 = 0x30300263,
@@ -592,6 +639,7 @@ static void __init tegra_p1852_init(void)
p1852_gpio_init();
p1852_uart_init();
p1852_usb_init();
+ tegra_io_dpd_init();
p1852_sdhci_init();
p1852_spi_init();
platform_add_devices(p1852_devices, ARRAY_SIZE(p1852_devices));
@@ -607,12 +655,29 @@ static void __init tegra_p1852_init(void)
static void __init tegra_p1852_reserve(void)
{
#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
- tegra_reserve(0, SZ_8M, 0);
+ tegra_reserve(0, SZ_8M, SZ_8M);
#else
- tegra_reserve(SZ_128M, SZ_8M, 0);
+ tegra_reserve(SZ_128M, SZ_8M, SZ_8M);
#endif
}
+int p1852_get_skuid()
+{
+ switch (system_rev) {
+ case TEGRA_P1852_SKU2_A00:
+ case TEGRA_P1852_SKU2_B00:
+ return 2;
+ case TEGRA_P1852_SKU5_A00:
+ case TEGRA_P1852_SKU5_B00:
+ return 5;
+ case TEGRA_P1852_SKU8_A00:
+ case TEGRA_P1852_SKU8_B00:
+ return 8;
+ default:
+ return -1;
+ }
+}
+
MACHINE_START(P1852, "p1852")
.boot_params = 0x80000100,
.init_irq = tegra_init_irq,
diff --git a/arch/arm/mach-tegra/board-p1852.h b/arch/arm/mach-tegra/board-p1852.h
index 1ac0968f9518..7de6a6b358e6 100644
--- a/arch/arm/mach-tegra/board-p1852.h
+++ b/arch/arm/mach-tegra/board-p1852.h
@@ -90,16 +90,28 @@
#define AC_PRESENT_INT (TPS6591X_INT_GPIO4 + TPS6591X_IRQ_BASE)
+/* List of P1852 skus - replicated from core/include/nvmachtypes.h */
+#define TEGRA_P1852_SKU2_A00 0x020000UL
+#define TEGRA_P1852_SKU2_B00 0x020200UL
+#define TEGRA_P1852_SKU5_A00 0x050000UL
+#define TEGRA_P1852_SKU5_B00 0x050200UL
+#define TEGRA_P1852_SKU8_A00 0x080000UL
+#define TEGRA_P1852_SKU8_B00 0x080200UL
+
int p1852_sdhci_init(void);
int p1852_pinmux_init(void);
+int p1852_pinmux_set_i2s4_master(void);
int p1852_panel_init(void);
int p1852_gpio_init(void);
int p1852_pins_state_init(void);
+int p1852_get_skuid(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-touch-kai-synaptics-spi.c b/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
index 989cf3339be4..718047acf896 100644
--- a/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
+++ b/arch/arm/mach-tegra/board-touch-kai-synaptics-spi.c
@@ -38,11 +38,9 @@ static struct rmi_f19_button_map synaptics_button_map = {
static int synaptics_touchpad_gpio_setup(void *gpio_data, bool configure)
{
if (configure) {
- tegra_gpio_enable(SYNAPTICS_ATTN_GPIO);
gpio_request(SYNAPTICS_ATTN_GPIO, "synaptics-irq");
gpio_direction_input(SYNAPTICS_ATTN_GPIO);
- tegra_gpio_enable(SYNAPTICS_RESET_GPIO);
gpio_request(SYNAPTICS_RESET_GPIO, "synaptics-reset");
gpio_direction_output(SYNAPTICS_RESET_GPIO, 0);
@@ -52,8 +50,6 @@ static int synaptics_touchpad_gpio_setup(void *gpio_data, bool configure)
} else {
gpio_free(SYNAPTICS_ATTN_GPIO);
gpio_free(SYNAPTICS_RESET_GPIO);
- tegra_gpio_disable(SYNAPTICS_ATTN_GPIO);
- tegra_gpio_disable(SYNAPTICS_RESET_GPIO);
}
return 0;
}
diff --git a/arch/arm/mach-tegra/board-touch-raydium_spi.c b/arch/arm/mach-tegra/board-touch-raydium_spi.c
index eb13fc4a44ab..b4ed0310054c 100644
--- a/arch/arm/mach-tegra/board-touch-raydium_spi.c
+++ b/arch/arm/mach-tegra/board-touch-raydium_spi.c
@@ -201,11 +201,9 @@ struct spi_board_info rm31080a_spi_board[1] = {
int __init touch_init_raydium(int irq_gpio, int reset_gpio, int platform)
{
int err = 0;
- tegra_gpio_enable(irq_gpio);
gpio_request(irq_gpio, "raydium-irq");
gpio_direction_input(irq_gpio);
- tegra_gpio_enable(reset_gpio);
gpio_request(reset_gpio, "raydium-reset");
gpio_direction_output(reset_gpio, 0);
diff --git a/arch/arm/mach-tegra/board-ventana-pinmux.c b/arch/arm/mach-tegra/board-ventana-pinmux.c
index eb371384ed4c..43b4b75878a2 100644
--- a/arch/arm/mach-tegra/board-ventana-pinmux.c
+++ b/arch/arm/mach-tegra/board-ventana-pinmux.c
@@ -181,6 +181,7 @@ static struct tegra_gpio_table gpio_table[] = {
{ .gpio = TEGRA_GPIO_HP_DET, .enable = true },
{ .gpio = TEGRA_GPIO_INT_MIC_EN, .enable = true },
{ .gpio = TEGRA_GPIO_EXT_MIC_EN, .enable = true },
+ { .gpio = TEGRA_GPIO_USB1_VBUS, .enable = false },
};
int __init ventana_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-ventana.c b/arch/arm/mach-tegra/board-ventana.c
index c8c9ac49745f..500118114b39 100644
--- a/arch/arm/mach-tegra/board-ventana.c
+++ b/arch/arm/mach-tegra/board-ventana.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/board-ventana.c
*
* Copyright (c) 2010-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
@@ -49,7 +50,7 @@
#include <mach/iomap.h>
#include <mach/io.h>
#include <mach/i2s.h>
-#include <mach/tegra_wm8903_pdata.h>
+#include <mach/tegra_asoc_pdata.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -350,12 +351,25 @@ static struct platform_device tegra_camera = {
.id = -1,
};
-static struct tegra_wm8903_platform_data ventana_audio_pdata = {
+static struct tegra_asoc_platform_data ventana_audio_pdata = {
.gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
.gpio_hp_det = TEGRA_GPIO_HP_DET,
.gpio_hp_mute = -1,
.gpio_int_mic_en = TEGRA_GPIO_INT_MIC_EN,
.gpio_ext_mic_en = TEGRA_GPIO_EXT_MIC_EN,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = -1,
+ },
+ .i2s_param[BT_SCO] = {
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ },
};
static struct platform_device ventana_audio_device = {
@@ -410,9 +424,6 @@ static struct i2c_board_info __initdata i2c_info[] = {
static int __init ventana_touch_init_atmel(void)
{
- tegra_gpio_enable(TEGRA_GPIO_PV6);
- tegra_gpio_enable(TEGRA_GPIO_PQ7);
-
gpio_request(TEGRA_GPIO_PV6, "atmel-irq");
gpio_direction_input(TEGRA_GPIO_PV6);
@@ -441,9 +452,6 @@ static struct i2c_board_info __initdata ventana_i2c_bus1_touch_info[] = {
static int __init ventana_touch_init_panjit(void)
{
- tegra_gpio_enable(TEGRA_GPIO_PV6);
-
- tegra_gpio_enable(TEGRA_GPIO_PQ7);
i2c_register_board_info(0, ventana_i2c_bus1_touch_info, 1);
return 0;
@@ -457,7 +465,6 @@ static int __init ventana_gps_init(void)
clk_enable(clk32);
}
- tegra_gpio_enable(TEGRA_GPIO_PZ3);
return 0;
}
@@ -495,7 +502,7 @@ static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
.vbus_reg = NULL,
.hot_plug = true,
.remote_wakeup_supported = false,
- .power_off_on_suspend = true,
+ .power_off_on_suspend = false,
},
.u_cfg.utmi = {
.hssync_start_delay = 9,
@@ -514,9 +521,6 @@ static void ulpi_link_platform_open(void)
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);
}
@@ -558,7 +562,7 @@ static struct tegra_usb_platform_data tegra_ehci3_utmi_pdata = {
.vbus_reg = NULL,
.hot_plug = true,
.remote_wakeup_supported = false,
- .power_off_on_suspend = true,
+ .power_off_on_suspend = false,
},
.u_cfg.utmi = {
.hssync_start_delay = 9,
@@ -648,12 +652,18 @@ void __init tegra_ventana_reserve(void)
tegra_ram_console_debug_reserve(SZ_1M);
}
+static const char *ventana_dt_board_compat[] = {
+ "nvidia,ventana",
+ NULL
+};
+
MACHINE_START(VENTANA, "ventana")
.boot_params = 0x00000100,
.map_io = tegra_map_common_io,
- .reserve = tegra_ventana_reserve,
.init_early = tegra_init_early,
- .init_irq = tegra_init_irq,
+ .init_irq = tegra_init_irq,
+ .reserve = tegra_ventana_reserve,
.timer = &tegra_timer,
- .init_machine = tegra_ventana_init,
+ .init_machine = tegra_ventana_init,
+ .dt_compat = ventana_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-tegra/board-ventana.h b/arch/arm/mach-tegra/board-ventana.h
index b8d8040d187b..8ebf4c9b3c4a 100644
--- a/arch/arm/mach-tegra/board-ventana.h
+++ b/arch/arm/mach-tegra/board-ventana.h
@@ -87,6 +87,9 @@ int ventana_cam_fixed_voltage_regulator_init(void);
#define TEGRA_GPIO_INT_MIC_EN TEGRA_GPIO_PX0
#define TEGRA_GPIO_EXT_MIC_EN TEGRA_GPIO_PX1
+/* Usb1 vbus GPIO */
+#define TEGRA_GPIO_USB1_VBUS TEGRA_GPIO_PD0
+
/* AC detect GPIO */
#define AC_PRESENT_GPIO TEGRA_GPIO_PV3
diff --git a/arch/arm/mach-tegra/board-whistler.c b/arch/arm/mach-tegra/board-whistler.c
index 06e704e47870..492367076170 100644
--- a/arch/arm/mach-tegra/board-whistler.c
+++ b/arch/arm/mach-tegra/board-whistler.c
@@ -352,12 +352,32 @@ static struct platform_device tegra_camera = {
};
static struct tegra_asoc_platform_data whistler_audio_pdata = {
- .gpio_spkr_en = -1,
- .gpio_hp_det = TEGRA_GPIO_HP_DET,
- .gpio_hp_mute = -1,
- .gpio_int_mic_en = -1,
- .gpio_ext_mic_en = -1,
- .debounce_time_hp = 200,
+ .gpio_spkr_en = -1,
+ .gpio_hp_det = TEGRA_GPIO_HP_DET,
+ .gpio_hp_mute = -1,
+ .gpio_int_mic_en = -1,
+ .gpio_ext_mic_en = -1,
+ .debounce_time_hp = 200,
+ .i2s_param[HIFI_CODEC] = {
+ .audio_port_id = 0,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_I2S,
+ .sample_size = 16,
+ },
+ .i2s_param[BASEBAND] = {
+ .audio_port_id = 2,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ .sample_size = 16,
+ .rate = 8000,
+ .channels = 1,
+ },
+ .i2s_param[BT_SCO] = {
+ .sample_size = 16,
+ .audio_port_id = 3,
+ .is_i2s_master = 1,
+ .i2s_mode = TEGRA_DAIFMT_DSP_A,
+ },
};
static struct platform_device whistler_audio_aic326x_device = {
@@ -421,6 +441,7 @@ static int __init whistler_touch_init(void)
static struct tegra_usb_platform_data tegra_udc_pdata = {
.port_otg = true,
.has_hostpc = false,
+ .builtin_host_disabled = true,
.phy_intf = TEGRA_USB_PHY_INTF_UTMI,
.op_mode = TEGRA_USB_OPMODE_DEVICE,
.u_data.dev = {
@@ -445,6 +466,7 @@ static struct tegra_usb_platform_data tegra_udc_pdata = {
static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
.port_otg = true,
.has_hostpc = false,
+ .builtin_host_disabled = true,
.phy_intf = TEGRA_USB_PHY_INTF_UTMI,
.op_mode = TEGRA_USB_OPMODE_HOST,
.u_data.host = {
@@ -517,12 +539,18 @@ void __init tegra_whistler_reserve(void)
tegra_ram_console_debug_reserve(SZ_1M);
}
+static const char *whistler_dt_board_compat[] = {
+ "nvidia,whistler",
+ NULL
+};
+
MACHINE_START(WHISTLER, "whistler")
.boot_params = 0x00000100,
.map_io = tegra_map_common_io,
- .reserve = tegra_whistler_reserve,
.init_early = tegra_init_early,
.init_irq = tegra_init_irq,
+ .reserve = tegra_whistler_reserve,
.timer = &tegra_timer,
.init_machine = tegra_whistler_init,
+ .dt_compat = whistler_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 7c081fad642a..85d02d501b63 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -72,9 +72,9 @@
#define COMMCHIP_UNKNOWN 0
#define COMMCHIP_NOCHIP 1
#define COMMCHIP_BROADCOM_BCM4329 2
-#define COMMCHIP BROADCOM_BCM4330 3
+#define COMMCHIP_BROADCOM_BCM4330 3
#define COMMCHIP_MARVELL_SD8797 4
-
+#define COMMCHIP_TI_WL18XX 5
struct memory_accessor;
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index d2e510818042..754a3fbaef20 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -69,6 +69,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
+#include <trace/events/power.h>
#include <asm/cputime.h>
#include <mach/clk.h>
@@ -286,6 +287,7 @@ static inline bool clk_cansleep(struct clk *c)
static inline void clk_lock_save(struct clk *c, unsigned long *flags)
{
+ trace_clock_lock(c->name, c->rate, smp_processor_id());
if (clk_cansleep(c)) {
*flags = 0;
mutex_lock(&c->mutex);
@@ -300,6 +302,7 @@ static inline void clk_unlock_restore(struct clk *c, unsigned long *flags)
mutex_unlock(&c->mutex);
else
spin_unlock_irqrestore(&c->spinlock, *flags);
+ trace_clock_unlock(c->name, c->rate, smp_processor_id());
}
static inline void clk_lock_init(struct clk *c)
diff --git a/arch/arm/mach-tegra/clocks_stats.c b/arch/arm/mach-tegra/clocks_stats.c
new file mode 100644
index 000000000000..1018a24ddbf9
--- /dev/null
+++ b/arch/arm/mach-tegra/clocks_stats.c
@@ -0,0 +1,259 @@
+/*
+ * arch/arm/mach-tegra/clocks_stats.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/list.h>
+
+#include "clock.h"
+
+#define STATS_TABLE_MAX_SIZE 64
+
+/*
+ * Generic stats tracking structures and functions
+ */
+struct stats_entry {
+ int rate;
+ cputime64_t time_at_rate;
+};
+
+struct stats_table {
+ struct stats_entry *entry;
+ int last_rate;
+ cputime64_t last_updated;
+ spinlock_t spinlock;
+ unsigned int num_entries;
+};
+
+struct clock_data {
+ struct dentry *dentry;
+ struct list_head node;
+ struct stats_table table;
+ struct notifier_block rate_change_nb;
+};
+
+static LIST_HEAD(clock_stats);
+static struct dentry *clock_debugfs_root;
+
+/*
+ * Initialize a stats table to zeros
+ */
+static void init_stats_table(struct stats_table *table)
+{
+ table->last_rate = -1;
+ spin_lock_init(&(table->spinlock));
+ table->num_entries = 0;
+ table->last_updated = get_jiffies_64();
+}
+
+/*
+ * Populate table with possible rates
+ */
+static int populate_rates(struct stats_table *table, struct clk *c)
+{
+ unsigned long rate = 0, rounded_rate = 0;
+ unsigned int num_rates = 0;
+ int i = 0;
+
+ /* Calculate number of rates */
+ while (rate <= c->max_rate) {
+ rounded_rate = c->ops->round_rate(c, rate);
+ if (IS_ERR_VALUE(rounded_rate) || (rounded_rate <= rate))
+ break;
+
+ num_rates++;
+ rate = rounded_rate + 2000; /* 2kHz resolution */
+ }
+
+ /* Allocate space for a table of that size */
+ table->entry = kmalloc(num_rates * sizeof(struct stats_entry),
+ GFP_KERNEL);
+ if (!table->entry)
+ return -ENOMEM;
+ rate = 0;
+ i = 0;
+
+ /* Populate table with possible rates */
+ while (rate <= c->max_rate) {
+ rounded_rate = c->ops->round_rate(c, rate);
+ if (IS_ERR_VALUE(rounded_rate) || (rounded_rate <= rate))
+ break;
+
+ table->entry[i].rate = rounded_rate;
+ table->entry[i].time_at_rate = 0;
+ i++;
+ rate = rounded_rate + 2000; /* 2kHz resolution */
+ }
+
+ table->num_entries = num_rates;
+
+ return 0;
+}
+
+/*
+ * Function is called whenever a rate changes. The time spent
+ * in the 'old rate' is finalized and the new rate is tracked.
+ * Entries are tracked in increasing order of rate
+ */
+static void update_stats_table(struct stats_table *table, int new_rate)
+{
+ int i = 0;
+ unsigned long flags;
+ u64 cur_jiffies = get_jiffies_64();
+
+ spin_lock_irqsave(&table->spinlock, flags);
+
+ if (new_rate == -1)
+ new_rate = table->last_rate;
+
+ /* update time spent on old clock */
+ for (i = 0; i < table->num_entries; i++) {
+ if (table->entry[i].rate == table->last_rate) {
+ table->entry[i].time_at_rate = cputime64_add(
+ table->entry[i].time_at_rate,
+ cputime64_sub(cur_jiffies,
+ table->last_updated));
+ }
+ }
+
+ table->last_updated = cur_jiffies;
+ table->last_rate = new_rate;
+
+ spin_unlock_irqrestore(&table->spinlock, flags);
+
+}
+
+/*
+ * Print stats table to seq_file
+ */
+static void dump_stats_table(struct seq_file *s, struct stats_table *table)
+{
+ int i = 0;
+ update_stats_table(table, -1);
+
+ seq_printf(s, "%-10s %-10s\n", "rate kHz", "time");
+ for (i = 0; i < table->num_entries; i++) {
+ seq_printf(s, "%-10lu %-10llu\n",
+ (long unsigned int)(table->entry[i].rate/1000),
+ cputime64_to_clock_t(table->entry[i].time_at_rate));
+ }
+}
+
+static int stats_show(struct seq_file *s, void *data)
+{
+ struct clock_data *d = (struct clock_data *)(s->private);
+ dump_stats_table(s, &d->table);
+ return 0;
+}
+
+static int stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, stats_show, inode->i_private);
+}
+
+static const struct file_operations clock_stats_fops = {
+ .open = stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
+ * Clock rate change notification callback
+ */
+static int rate_notify_cb(struct notifier_block *nb, unsigned long rate,
+ void *v)
+{
+ struct clock_data *c =
+ container_of(nb, struct clock_data, rate_change_nb);
+ update_stats_table(&c->table, rate);
+ return NOTIFY_OK;
+}
+
+/*
+ * Call once for each clock to track
+ */
+static int track_clock(char *clk_name)
+{
+ int ret = 0;
+ struct clock_data *d;
+ struct clk *c = clk_get(NULL, clk_name);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+
+ d = kmalloc(sizeof(struct clock_data), GFP_KERNEL);
+ if (d == NULL)
+ goto err_clk;
+
+ d->rate_change_nb.notifier_call = rate_notify_cb;
+
+ if (!clock_debugfs_root)
+ goto err_clk;
+
+ d->dentry = debugfs_create_file(
+ clk_name, S_IRUGO, clock_debugfs_root, d, &clock_stats_fops);
+ if (!d->dentry)
+ goto err_clk;
+
+ init_stats_table(&d->table);
+ ret = populate_rates(&d->table, c);
+ if (ret)
+ goto err_out;
+
+ ret = tegra_register_clk_rate_notifier(c, &d->rate_change_nb);
+ if (ret)
+ goto err_out;
+
+ list_add(&d->node, &clock_stats);
+
+ clk_put(c);
+ return 0;
+
+err_out:
+ kfree(d->table.entry);
+ debugfs_remove(d->dentry);
+err_clk:
+ kfree(d);
+ clk_put(c);
+ return -ENOMEM;
+}
+
+static int __init tegra_clocks_debug_init(void)
+{
+ int ret = 0;
+
+ clock_debugfs_root = debugfs_create_dir("clock_stats", NULL);
+ if (!clock_debugfs_root)
+ return -ENOMEM;
+
+ /* Start tracking individual clocks */
+ ret = track_clock("sbus");
+ if (0 != ret)
+ goto err_out;
+
+ ret = track_clock("cbus");
+ if (0 != ret)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ return ret;
+
+}
+late_initcall(tegra_clocks_debug_init);
diff --git a/arch/arm/mach-tegra/common-t3.c b/arch/arm/mach-tegra/common-t3.c
index 2da656f97c38..76188723b46f 100644
--- a/arch/arm/mach-tegra/common-t3.c
+++ b/arch/arm/mach-tegra/common-t3.c
@@ -3,7 +3,7 @@
*
* Tegra 3 SoC-specific initialization (memory controller, etc.)
*
- * 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
@@ -44,6 +44,8 @@
((MC_EMEM_ARB_TIMING_W2R - MC_EMEM_ARB_CFG) / 4 + 1)
#define MC_TIMING_REG_NUM2 \
((MC_EMEM_ARB_MISC1 - MC_EMEM_ARB_DA_TURNS) / 4 + 1)
+#define MC_TIMING_REG_NUM3 \
+ ((MC_LATENCY_ALLOWANCE_VI_2 - MC_LATENCY_ALLOWANCE_AFI) / 4 + 1)
struct mc_client {
const char *name;
@@ -59,7 +61,8 @@ static void __iomem *mc = IO_ADDRESS(TEGRA_MC_BASE);
#ifdef CONFIG_PM_SLEEP
-static u32 mc_boot_timing[MC_TIMING_REG_NUM1 + MC_TIMING_REG_NUM2 + 4];
+static u32 mc_boot_timing[MC_TIMING_REG_NUM1 + MC_TIMING_REG_NUM2
+ + MC_TIMING_REG_NUM3 + 4];
static void tegra_mc_timing_save(void)
{
@@ -76,6 +79,10 @@ static void tegra_mc_timing_save(void)
*ctx++ = readl((u32)mc + MC_EMEM_ARB_OVERRIDE);
*ctx++ = readl((u32)mc + MC_RESERVED_RSV);
+ for (off = MC_LATENCY_ALLOWANCE_AFI; off <= MC_LATENCY_ALLOWANCE_VI_2;
+ off += 4)
+ *ctx++ = readl((u32)mc + off);
+
*ctx++ = readl((u32)mc + MC_INT_MASK);
}
@@ -94,6 +101,10 @@ void tegra_mc_timing_restore(void)
__raw_writel(*ctx++, (u32)mc + MC_EMEM_ARB_OVERRIDE);
__raw_writel(*ctx++, (u32)mc + MC_RESERVED_RSV);
+ for (off = MC_LATENCY_ALLOWANCE_AFI; off <= MC_LATENCY_ALLOWANCE_VI_2;
+ off += 4)
+ __raw_writel(*ctx++, (u32)mc + off);
+
writel(*ctx++, (u32)mc + MC_INT_MASK);
off = readl((u32)mc + MC_INT_MASK);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 3a4f86079053..a34d37f2f250 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/common.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (C) 2010-2012, NVIDIA Corporation. All rights reserved.
*
* Author:
* Colin Cross <ccross@android.com>
@@ -29,6 +29,7 @@
#include <linux/bitops.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
+#include <linux/of.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/system.h>
@@ -220,6 +221,7 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ "sbc5.sclk", NULL, 40000000, false},
{ "sbc6.sclk", NULL, 40000000, false},
{ "wake.sclk", NULL, 40000000, true },
+ { "cpu_mode.sclk", NULL, 80000000, false },
{ "cbus", "pll_c", 416000000, false },
{ "pll_c_out1", "pll_c", 208000000, false },
{ "mselect", "pll_p", 102000000, true },
@@ -227,61 +229,11 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
{ NULL, NULL, 0, 0},
};
-#ifdef CONFIG_CACHE_L2X0
#ifdef CONFIG_TRUSTED_FOUNDATIONS
-static void tegra_cache_smc(bool enable, u32 arg)
+static inline void tegra_l2x0_disable_tz(void)
{
- void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
- bool need_affinity_switch;
- bool can_switch_affinity;
- bool l2x0_enabled;
- cpumask_t local_cpu_mask;
- cpumask_t saved_cpu_mask;
- unsigned long flags;
- long ret;
-
- /*
- * ISSUE : Some registers of PL310 controler must be written
- * from Secure context (and from CPU0)!
- *
- * When called form Normal we obtain an abort or do nothing.
- * Instructions that must be called in Secure:
- * - Write to Control register (L2X0_CTRL==0x100)
- * - Write in Auxiliary controler (L2X0_AUX_CTRL==0x104)
- * - Invalidate all entries (L2X0_INV_WAY==0x77C),
- * mandatory at boot time.
- * - Tag and Data RAM Latency Control Registers
- * (0x108 & 0x10C) must be written in Secure.
- */
- need_affinity_switch = (smp_processor_id() != 0);
- can_switch_affinity = !irqs_disabled();
-
- WARN_ON(need_affinity_switch && !can_switch_affinity);
- if (need_affinity_switch && can_switch_affinity) {
- cpu_set(0, local_cpu_mask);
- sched_getaffinity(0, &saved_cpu_mask);
- ret = sched_setaffinity(0, &local_cpu_mask);
- WARN_ON(ret != 0);
- }
-
- local_irq_save(flags);
- l2x0_enabled = readl_relaxed(p + L2X0_CTRL) & 1;
- if (enable && !l2x0_enabled)
- tegra_generic_smc(0xFFFFF100, 0x00000001, arg);
- else if (!enable && l2x0_enabled)
- tegra_generic_smc(0xFFFFF100, 0x00000002, arg);
- local_irq_restore(flags);
-
- if (need_affinity_switch && can_switch_affinity) {
- ret = sched_setaffinity(0, &saved_cpu_mask);
- WARN_ON(ret != 0);
- }
-}
-
-static void tegra_l2x0_disable(void)
-{
- unsigned long flags;
static u32 l2x0_way_mask;
+ BUG_ON(smp_processor_id() != 0);
if (!l2x0_way_mask) {
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
@@ -292,30 +244,75 @@ static void tegra_l2x0_disable(void)
ways = (aux_ctrl & (1 << 16)) ? 16 : 8;
l2x0_way_mask = (1 << ways) - 1;
}
-
- local_irq_save(flags);
- tegra_cache_smc(false, l2x0_way_mask);
- local_irq_restore(flags);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ /* flush all ways on any disable */
+ tegra_generic_smc_uncached(0xFFFFF100, 0x00000002, l2x0_way_mask);
+#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ if (tegra_is_cpu_in_lp2(0) == false) {
+ /*
+ * If entering LP0/LP1, ask secureos to fully flush and
+ * disable the L2.
+ *
+ * If entering LP2, L2 disable is handled by the secureos
+ * as part of the tegra_sleep_cpu() SMC. This SMC indicates
+ * no more secureos tasks will be scheduled, allowing it
+ * to optimize out L2 flushes on its side.
+ */
+ tegra_generic_smc_uncached(0xFFFFF100,
+ 0x00000002, l2x0_way_mask);
+ }
+#endif
}
-#endif /* CONFIG_TRUSTED_FOUNDATIONS */
-void tegra_init_cache(bool init)
+static inline void tegra_init_cache_tz(bool init)
{
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
u32 aux_ctrl;
-#ifdef CONFIG_TRUSTED_FOUNDATIONS
- /* issue the SMC to enable the L2 */
- aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
- tegra_cache_smc(true, aux_ctrl);
+ BUG_ON(smp_processor_id() != 0);
+
+ if (init) {
+ /* init L2 from secureos */
+ tegra_generic_smc(0xFFFFF100, 0x00000001, 0x0);
+
+ /* common init called for outer call hookup */
+ aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
+ l2x0_init(p, aux_ctrl, 0xFFFFFFFF);
+
+ /* use our outer_disable() routine */
+ outer_cache.disable = tegra_l2x0_disable_tz;
+ } else {
+ /* reenable L2 in secureos */
+ aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
+ tegra_generic_smc_uncached(0xFFFFF100, 0x00000004, aux_ctrl);
+ }
+}
+#endif /* CONFIG_TRUSTED_FOUNDATIONS */
- /* after init, reread aux_ctrl and register handlers */
- aux_ctrl = readl_relaxed(p + L2X0_AUX_CTRL);
- l2x0_init(p, aux_ctrl, 0xFFFFFFFF);
+#ifdef CONFIG_CACHE_L2X0
+/*
+ * We define our own outer_disable() to avoid L2 flush upon LP2 entry.
+ * Since the Tegra kernel will always be in single core mode when
+ * L2 is being disabled, we can omit the locking. Since we are not
+ * accessing the spinlock we also avoid the problem of the spinlock
+ * storage getting out of sync.
+ */
+static inline void tegra_l2x0_disable(void)
+{
+ void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
+ writel_relaxed(0, p + L2X0_CTRL);
+ dsb();
+}
- /* override outer_disable() with our disable */
- outer_cache.disable = tegra_l2x0_disable;
+void tegra_init_cache(bool init)
+{
+#ifdef CONFIG_TRUSTED_FOUNDATIONS
+ /* enable/re-enable of L2 handled by secureos */
+ return tegra_init_cache_tz(init);
#else
+ void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
+ u32 aux_ctrl;
+
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
@@ -353,6 +350,8 @@ void tegra_init_cache(bool init)
aux_ctrl |= 0x7C000001;
if (init) {
l2x0_init(p, aux_ctrl, 0x8200c3fe);
+ /* use our outer_disable() routine to avoid flush */
+ outer_cache.disable = tegra_l2x0_disable;
} else {
u32 tmp;
@@ -365,7 +364,7 @@ void tegra_init_cache(bool init)
l2x0_enable();
#endif
}
-#endif
+#endif /* CONFIG_CACHE_L2X0 */
static void __init tegra_init_power(void)
{
@@ -676,11 +675,54 @@ __setup("audio_codec=", tegra_audio_codec_type);
void tegra_get_board_info(struct board_info *bi)
{
- bi->board_id = (system_serial_high >> 16) & 0xFFFF;
- bi->sku = (system_serial_high) & 0xFFFF;
- bi->fab = (system_serial_low >> 24) & 0xFF;
- bi->major_revision = (system_serial_low >> 16) & 0xFF;
- bi->minor_revision = (system_serial_low >> 8) & 0xFF;
+#ifdef CONFIG_OF
+ struct device_node *board_info;
+ u32 prop_val;
+ int err;
+
+ board_info = of_find_node_by_path("/chosen/board_info");
+ if (!IS_ERR_OR_NULL(board_info)) {
+ memset(bi, 0, sizeof(*bi));
+
+ err = of_property_read_u32(board_info, "id", &prop_val);
+ if (err)
+ pr_err("failed to read /chosen/board_info/id\n");
+ else
+ bi->board_id = prop_val;
+
+ err = of_property_read_u32(board_info, "sku", &prop_val);
+ if (err)
+ pr_err("failed to read /chosen/board_info/sku\n");
+ else
+ bi->sku = prop_val;
+
+ err = of_property_read_u32(board_info, "fab", &prop_val);
+ if (err)
+ pr_err("failed to read /chosen/board_info/fab\n");
+ else
+ bi->fab = prop_val;
+
+ err = of_property_read_u32(board_info, "major_revision", &prop_val);
+ if (err)
+ pr_err("failed to read /chosen/board_info/major_revision\n");
+ else
+ bi->major_revision = prop_val;
+
+ err = of_property_read_u32(board_info, "minor_revision", &prop_val);
+ if (err)
+ pr_err("failed to read /chosen/board_info/minor_revision\n");
+ else
+ bi->minor_revision = prop_val;
+ } else {
+#endif
+ bi->board_id = (system_serial_high >> 16) & 0xFFFF;
+ bi->sku = (system_serial_high) & 0xFFFF;
+ bi->fab = (system_serial_low >> 24) & 0xFF;
+ bi->major_revision = (system_serial_low >> 16) & 0xFF;
+ bi->minor_revision = (system_serial_low >> 8) & 0xFF;
+#ifdef CONFIG_OF
+ }
+#endif
}
static int __init tegra_pmu_board_info(char *info)
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 9bed9270b412..ea5bbcf237c0 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -7,7 +7,7 @@
* Colin Cross <ccross@google.com>
* Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
*
- * 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
@@ -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, &edp_cpumask, true);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true, 0);
if (target_cpu_speed[0]) {
edp_update_limit();
tegra_cpu_set_speed_cap(NULL);
}
- tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
+ tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false, 0);
mutex_unlock(&tegra_cpu_lock);
return ret;
@@ -321,31 +321,31 @@ 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);
new_speed = edp_governor_speed(cpu_speed);
if (new_speed < cpu_speed) {
ret = tegra_cpu_set_speed_cap(NULL);
- if (ret) {
- cpu_clear(cpu, edp_cpumask);
- edp_update_limit();
- }
-
- printk(KERN_DEBUG "tegra CPU:%sforce EDP limit %u kHz"
+ printk(KERN_DEBUG "cpu-tegra:%sforce EDP limit %u kHz"
"\n", ret ? " failed to " : " ", new_speed);
}
- tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false);
+ if (!ret)
+ ret = tegra_cpu_dvfs_alter(
+ edp_thermal_index, &edp_cpumask, false, event);
+ if (ret) {
+ cpu_clear(cpu, edp_cpumask);
+ edp_update_limit();
+ }
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);
+ tegra_cpu_dvfs_alter(
+ edp_thermal_index, &edp_cpumask, true, event);
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;
}
diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c
index 051381297f6f..c0d21bfa816a 100644
--- a/arch/arm/mach-tegra/cpu-tegra3.c
+++ b/arch/arm/mach-tegra/cpu-tegra3.c
@@ -3,7 +3,7 @@
*
* CPU auto-hotplug for Tegra3 CPUs
*
- * 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
@@ -41,7 +41,7 @@
#define INITIAL_STATE TEGRA_HP_DISABLED
#define UP2G0_DELAY_MS 70
#define UP2Gn_DELAY_MS 100
-#define DOWN_DELAY_MS 500
+#define DOWN_DELAY_MS 2000
static struct mutex *tegra3_cpu_lock;
@@ -189,10 +189,38 @@ enum {
};
#define NR_FSHIFT 2
-static unsigned int nr_run_thresholds[] = {
+
+static unsigned int rt_profile_sel;
+
+/* avg run threads * 4 (e.g., 9 = 2.25 threads) */
+
+static unsigned int rt_profile_default[] = {
/* 1, 2, 3, 4 - on-line cpus target */
- 5, 9, 10, UINT_MAX /* avg run threads * 4 (e.g., 9 = 2.25 threads) */
+ 5, 9, 10, UINT_MAX
+};
+
+static unsigned int rt_profile_1[] = {
+/* 1, 2, 3, 4 - on-line cpus target */
+ 8, 9, 10, UINT_MAX
+};
+
+static unsigned int rt_profile_2[] = {
+/* 1, 2, 3, 4 - on-line cpus target */
+ 5, 13, 14, UINT_MAX
+};
+
+static unsigned int rt_profile_off[] = { /* disables runable thread */
+ 0, 0, 0, UINT_MAX
+};
+
+static unsigned int *rt_profiles[] = {
+ rt_profile_default,
+ rt_profile_1,
+ rt_profile_2,
+ rt_profile_off
};
+
+
static unsigned int nr_run_hysteresis = 2; /* 0.5 thread */
static unsigned int nr_run_last;
@@ -216,8 +244,10 @@ static noinline int tegra_cpu_speed_balance(void)
* 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];
+
+ unsigned int *current_profile = rt_profiles[rt_profile_sel];
+ for (nr_run = 1; nr_run < ARRAY_SIZE(rt_profile_default); nr_run++) {
+ unsigned int nr_threshold = current_profile[nr_run - 1];
if (nr_run_last <= nr_run)
nr_threshold += nr_run_hysteresis;
if (avg_nr_run <= (nr_threshold << (FSHIFT - NR_FSHIFT)))
@@ -330,7 +360,7 @@ 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()) {
+ if ((n >= 1) && is_lp_cluster() && !no_lp) {
/* 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);
@@ -527,6 +557,25 @@ static const struct file_operations hp_stats_fops = {
.release = single_release,
};
+static int rt_bias_get(void *data, u64 *val)
+{
+ *val = rt_profile_sel;
+ return 0;
+}
+static int rt_bias_set(void *data, u64 val)
+{
+ if (val < ARRAY_SIZE(rt_profiles))
+ rt_profile_sel = (u32)val;
+
+ pr_debug("rt_profile_sel set to %d\nthresholds are now [%d, %d, %d]\n",
+ rt_profile_sel,
+ rt_profiles[rt_profile_sel][0],
+ rt_profiles[rt_profile_sel][1],
+ rt_profiles[rt_profile_sel][2]);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(rt_bias_fops, rt_bias_get, rt_bias_set, "%llu\n");
+
static int min_cpus_get(void *data, u64 *val)
{
*val = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS);
@@ -577,6 +626,10 @@ static int __init tegra_auto_hotplug_debug_init(void)
"stats", S_IRUGO, hp_debugfs_root, NULL, &hp_stats_fops))
goto err_out;
+ if (!debugfs_create_file(
+ "core_bias", S_IRUGO, hp_debugfs_root, NULL, &rt_bias_fops))
+ goto err_out;
+
return 0;
err_out:
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index 47d5996e5961..25f63f6c4b2a 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -45,6 +45,7 @@
#include "cpuidle.h"
#include "pm.h"
#include "sleep.h"
+#include "timer.h"
int tegra_lp2_exit_latency;
static int tegra_lp2_power_off_time;
@@ -117,20 +118,25 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev,
return tegra_idle_enter_lp3(dev, state);
}
+ trace_printk("LP2 entry at %lu us\n",
+ (unsigned long)readl(IO_ADDRESS(TEGRA_TMR1_BASE)
+ + TIMERUS_CNTR_1US));
+
local_irq_disable();
enter = ktime_get();
tegra_cpu_idle_stats_lp2_ready(dev->cpu);
tegra_idle_lp2(dev, state);
+ trace_printk("LP2 exit at %lu us\n",
+ (unsigned long)readl(IO_ADDRESS(TEGRA_TMR1_BASE)
+ + TIMERUS_CNTR_1US));
+
exit = ktime_sub(ktime_get(), enter);
us = ktime_to_us(exit);
local_irq_enable();
- /* cpu clockevents may have been reset by powerdown */
- hrtimer_peek_ahead_timers();
-
smp_rmb();
/* Update LP2 latency provided no fall back to LP3 */
diff --git a/arch/arm/mach-tegra/cpuquiet.c b/arch/arm/mach-tegra/cpuquiet.c
index 26adce230920..87aebfe7badb 100644
--- a/arch/arm/mach-tegra/cpuquiet.c
+++ b/arch/arm/mach-tegra/cpuquiet.c
@@ -134,7 +134,7 @@ static void apply_core_config(void)
static void tegra_cpuquiet_work_func(struct work_struct *work)
{
- bool update_cr_config = false;
+ int device_busy = -1;
mutex_lock(tegra3_cpu_lock);
@@ -148,7 +148,7 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
/*catch-up with governor target speed */
tegra_cpu_set_speed_cap(NULL);
/* process pending core requests*/
- update_cr_config = true;
+ device_busy = 0;
}
}
break;
@@ -159,6 +159,7 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
if (!clk_set_parent(cpu_clk, cpu_lp_clk)) {
/*catch-up with governor target speed*/
tegra_cpu_set_speed_cap(NULL);
+ device_busy = 1;
}
}
break;
@@ -169,8 +170,12 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
mutex_unlock(tegra3_cpu_lock);
- if (update_cr_config)
+ if (device_busy == 1) {
+ cpuquiet_device_busy();
+ } else if (!device_busy) {
apply_core_config();
+ cpuquiet_device_free();
+ }
}
static void min_max_constraints_workfunc(struct work_struct *work)
@@ -183,6 +188,9 @@ static void min_max_constraints_workfunc(struct work_struct *work)
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)
+ return;
+
if (is_lp_cluster())
return;
@@ -212,15 +220,22 @@ static void min_max_constraints_workfunc(struct work_struct *work)
static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
+ bool g_cluster = false;
+
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return NOTIFY_OK;
+
mutex_lock(tegra3_cpu_lock);
if ((n >= 1) && is_lp_cluster()) {
- /* make sure cpu rate is within g-mode range before switching */
+ /* 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);
+ g_cluster = true;
}
tegra_cpu_set_speed_cap(NULL);
@@ -228,11 +243,17 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
schedule_work(&minmax_work);
+ if (g_cluster)
+ cpuquiet_device_free();
+
return NOTIFY_OK;
}
static int max_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return NOTIFY_OK;
+
if (n < num_online_cpus())
schedule_work(&minmax_work);
@@ -253,6 +274,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
/* 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);
+ cpuquiet_device_free();
}
return;
}
@@ -306,11 +328,13 @@ static void enable_callback(struct cpuquiet_attribute *attr)
mutex_unlock(tegra3_cpu_lock);
cancel_delayed_work_sync(&cpuquiet_work);
pr_info("Tegra cpuquiet clusterswitch disabled\n");
+ cpuquiet_device_busy();
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);
+ cpuquiet_device_free();
}
mutex_unlock(tegra3_cpu_lock);
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 79f3ccc57f92..c3bc1ded475a 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -1723,6 +1723,43 @@ struct nvhost_device tegra_disp1_device = {
.num_resources = ARRAY_SIZE(tegra_disp1_resources),
};
+static struct resource tegra_disp2_resources[] = {
+ {
+ .name = "irq",
+ .start = INT_DISPLAY_B_GENERAL,
+ .end = INT_DISPLAY_B_GENERAL,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+ .start = TEGRA_DISPLAY2_BASE,
+ .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .flags = IORESOURCE_MEM,
+ .start = 0,
+ .end = 0,
+ },
+ {
+ .name = "hdmi_regs",
+ .start = TEGRA_HDMI_BASE,
+ .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct nvhost_device tegra_disp2_device = {
+ .name = "tegradc",
+ .id = 1,
+ .resource = tegra_disp2_resources,
+ .num_resources = ARRAY_SIZE(tegra_disp2_resources),
+ .dev = {
+ .platform_data = 0,
+ },
+};
+
struct platform_device tegra_nvmap_device = {
.name = "tegra-nvmap",
.id = -1,
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index c5cf7b708ec4..02962b59031f 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -132,6 +132,7 @@ extern struct platform_device debug_uarte_device;
#endif
extern struct nvhost_device tegra_disp1_device;
+extern struct nvhost_device tegra_disp2_device;
extern struct platform_device tegra_nvmap_device;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
extern struct platform_device tegra_cec_device;
diff --git a/arch/arm/mach-tegra/dvfs.c b/arch/arm/mach-tegra/dvfs.c
index cb33e3db862f..c36b81d2c402 100644
--- a/arch/arm/mach-tegra/dvfs.c
+++ b/arch/arm/mach-tegra/dvfs.c
@@ -38,6 +38,7 @@
#include "board.h"
#include "clock.h"
#include "dvfs.h"
+#include "timer.h"
#define DVFS_RAIL_STATS_BIN 25
#define DVFS_RAIL_STATS_SCALE 2
@@ -308,6 +309,13 @@ static int dvfs_rail_connect_to_regulator(struct dvfs_rail *rail)
rail->reg = reg;
}
+ v = regulator_enable(rail->reg);
+ if (v < 0) {
+ pr_err("tegra_dvfs: failed on enabling regulator %s\n, err %d",
+ rail->reg_id, v);
+ return v;
+ }
+
v = regulator_get_voltage(rail->reg);
if (v < 0) {
pr_err("tegra_dvfs: failed initial get %s voltage\n",
@@ -681,9 +689,13 @@ int __init tegra_dvfs_late_init(void)
{
bool connected = true;
struct dvfs_rail *rail;
+ int cur_linear_age = tegra_get_linear_age();
mutex_lock(&dvfs_lock);
+ if (cur_linear_age >= 0)
+ tegra_dvfs_age_cpu(cur_linear_age);
+
list_for_each_entry(rail, &dvfs_rail_list, node)
if (dvfs_rail_connect_to_regulator(rail))
connected = false;
diff --git a/arch/arm/mach-tegra/dvfs.h b/arch/arm/mach-tegra/dvfs.h
index 3bdb13690278..7cacd954b914 100644
--- a/arch/arm/mach-tegra/dvfs.h
+++ b/arch/arm/mach-tegra/dvfs.h
@@ -5,7 +5,7 @@
* Author:
* Colin Cross <ccross@google.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
@@ -21,8 +21,8 @@
#ifndef _TEGRA_DVFS_H_
#define _TEGRA_DVFS_H_
-#define MAX_DVFS_FREQS 20
-#define DVFS_RAIL_STATS_TOP_BIN 40
+#define MAX_DVFS_FREQS 40
+#define DVFS_RAIL_STATS_TOP_BIN 42
struct clk;
struct dvfs_rail;
@@ -118,8 +118,8 @@ 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, unsigned long *alt_freqs);
-void tegra_cpu_dvfs_alter(
- int edp_thermal_index, const cpumask_t *cpus, bool before_clk_update);
+int tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
+ bool before_clk_update, int cpu_event);
#else
static inline void tegra_soc_init_dvfs(void)
{}
@@ -157,19 +157,22 @@ static inline void tegra_dvfs_core_cap_level_set(int level)
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, const cpumask_t *cpus, bool before_clk_update)
+static inline int tegra_cpu_dvfs_alter(int edp_thermal_index,
+ const cpumask_t *cpus, bool before_clk_update, int cpu_event)
{}
#endif
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail);
int tegra_dvfs_rail_post_enable(struct dvfs_rail *rail);
+void tegra_dvfs_age_cpu(int cur_linear_age);
#else
static inline int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail)
{ return 0; }
static inline int tegra_dvfs_rail_post_enable(struct dvfs_rail *rail)
{ return 0; }
+static inline void tegra_dvfs_age_cpu(int cur_linear_age)
+{ return; }
#endif
#endif
diff --git a/arch/arm/mach-tegra/fuse.h b/arch/arm/mach-tegra/fuse.h
index 37f591af5695..0b04938988c7 100644
--- a/arch/arm/mach-tegra/fuse.h
+++ b/arch/arm/mach-tegra/fuse.h
@@ -36,6 +36,7 @@ int tegra_cpu_process_id(void);
int tegra_core_process_id(void);
int tegra_soc_speedo_id(void);
void tegra_init_speedo_data(void);
+int tegra_get_age(void);
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
int tegra_package_id(void);
diff --git a/arch/arm/mach-tegra/headsmp.S b/arch/arm/mach-tegra/headsmp.S
index 4e28a558cc38..2fa96381f68f 100644
--- a/arch/arm/mach-tegra/headsmp.S
+++ b/arch/arm/mach-tegra/headsmp.S
@@ -3,7 +3,7 @@
*
* CPU initialization routines for Tegra SoCs
*
- * Copyright (c) 2009-2011, NVIDIA Corporation.
+ * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved.
* Copyright (c) 2011 Google, Inc.
* Author: Colin Cross <ccross@android.com>
* Gary King <gking@nvidia.com>
@@ -82,16 +82,12 @@ ENTRY(tegra_resume)
mov32 r0, TEGRA_ARM_PERIF_BASE
ldr r1, [r0]
orr r1, r1, #1
-#if defined(CONFIG_HAVE_ARM_SCU)
- 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]
#ifdef CONFIG_TRUSTED_FOUNDATIONS
- /* wake up (should have specified args?) */
- bl tegra_generic_smc
+ /* wake up */
+ mov r0, #0x00000003
+ bl tegra_generic_smc_local
#endif
b tegra_cpu_resume_phys
diff --git a/arch/arm/mach-tegra/i2c_error_recovery.c b/arch/arm/mach-tegra/i2c_error_recovery.c
index a3ac4e122a8f..2993a6b3abc5 100644
--- a/arch/arm/mach-tegra/i2c_error_recovery.c
+++ b/arch/arm/mach-tegra/i2c_error_recovery.c
@@ -44,7 +44,6 @@ int arb_lost_recovery(int scl_gpio, int sda_gpio)
scl_gpio, ret);
return -EINVAL;;
}
- tegra_gpio_enable(scl_gpio);
ret = gpio_request(sda_gpio, "sda_gpio");
if (ret < 0) {
@@ -52,7 +51,6 @@ int arb_lost_recovery(int scl_gpio, int sda_gpio)
sda_gpio, ret);
goto err;
}
- tegra_gpio_enable(sda_gpio);
gpio_direction_input(sda_gpio);
while (retry--) {
@@ -82,9 +80,7 @@ int arb_lost_recovery(int scl_gpio, int sda_gpio)
}
gpio_free(scl_gpio);
- tegra_gpio_disable(scl_gpio);
gpio_free(sda_gpio);
- tegra_gpio_disable(sda_gpio);
if (likely(recovered_successfully)) {
pr_err("arbitration lost recovered by re-try-count 0x%08x\n",
@@ -97,7 +93,6 @@ int arb_lost_recovery(int scl_gpio, int sda_gpio)
err:
gpio_free(scl_gpio);
- tegra_gpio_disable(scl_gpio);
return ret;
}
diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h
index 97f02ce6e95d..d7aaed0bdcdc 100644
--- a/arch/arm/mach-tegra/include/mach/dc.h
+++ b/arch/arm/mach-tegra/include/mach/dc.h
@@ -24,6 +24,7 @@
#include <linux/pm.h>
#include <linux/types.h>
+#include <linux/fb.h>
#include <drm/drm_fixed.h>
#define TEGRA_MAX_DC 2
@@ -368,6 +369,8 @@ struct tegra_dc_out {
u8 *out_sel_configs;
unsigned n_out_sel_configs;
+ bool user_needs_vblank;
+ struct completion user_vblank_comp;
int (*enable)(void);
int (*postpoweron)(void);
@@ -525,6 +528,8 @@ bool tegra_dc_get_connected(struct tegra_dc *);
bool tegra_dc_hpd(struct tegra_dc *dc);
+void tegra_dc_get_fbvblank(struct tegra_dc *dc, struct fb_vblank *vblank);
+int tegra_dc_wait_for_vsync(struct tegra_dc *dc);
void tegra_dc_blank(struct tegra_dc *dc);
void tegra_dc_enable(struct tegra_dc *dc);
@@ -539,6 +544,9 @@ void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val);
*/
int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n);
int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n);
+int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable);
+bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts);
+bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts);
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode);
struct fb_videomode;
@@ -565,10 +573,6 @@ 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_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);
@@ -588,4 +592,8 @@ struct tegra_dc_edid {
struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc);
void tegra_dc_put_edid(struct tegra_dc_edid *edid);
+int tegra_dc_set_flip_callback(void (*callback)(void));
+int tegra_dc_unset_flip_callback(void);
+int tegra_dc_get_panel_sync_rate(void);
+
#endif
diff --git a/arch/arm/mach-tegra/include/mach/io_dpd.h b/arch/arm/mach-tegra/include/mach/io_dpd.h
index 8d153792b798..6eb05c3f1b93 100644
--- a/arch/arm/mach-tegra/include/mach/io_dpd.h
+++ b/arch/arm/mach-tegra/include/mach/io_dpd.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/io_dpd.h
*
- * 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
@@ -16,25 +16,23 @@
#ifndef __MACH_TEGRA_IO_DPD_H
#define __MACH_TEGRA_IO_DPD_H
+#include <linux/delay.h>
+
+/* Tegra io dpd entry - for each supported driver */
+struct tegra_io_dpd {
+ const char *name; /* driver name */
+ u8 io_dpd_reg_index; /* io dpd register index */
+ u8 io_dpd_bit; /* bit position for driver in dpd register */
+ u8 need_delay_dpd; /* work around to delay dpd after lp0*/
+ struct delayed_work delay_dpd;
+ struct mutex delay_lock;
+};
+
/* Tegra io dpd APIs */
-#ifdef CONFIG_PM_SLEEP
struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev); /* get handle */
void tegra_io_dpd_enable(struct tegra_io_dpd *hnd); /* enable dpd */
void tegra_io_dpd_disable(struct tegra_io_dpd *hnd); /* disable dpd */
-#else
-static inline struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev)
-{
- return NULL;
-}
-static inline void tegra_io_dpd_enable(struct tegra_io_dpd *hnd)
-{
- /* Do nothing */
-}
-static inline void tegra_io_dpd_disable(struct tegra_io_dpd *hnd)
-{
- /* Do nothing */
-}
-#endif
+int tegra_io_dpd_init(void);
#endif /* end __MACH_TEGRA_IO_DPD_H */
diff --git a/arch/arm/mach-tegra/include/mach/latency_allowance.h b/arch/arm/mach-tegra/include/mach/latency_allowance.h
index 8644075a88b3..9861834ad9de 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-2012 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
@@ -18,19 +18,19 @@
#define _MACH_TEGRA_LATENCY_ALLOWANCE_H_
enum tegra_la_id {
- TEGRA_LA_AFIR = 0,
- TEGRA_LA_AFIW,
+ TEGRA_LA_AFIR = 0, /* T30 specific */
+ TEGRA_LA_AFIW, /* T30 specific */
TEGRA_LA_AVPC_ARM7R,
TEGRA_LA_AVPC_ARM7W,
TEGRA_LA_DISPLAY_0A,
TEGRA_LA_DISPLAY_0B,
TEGRA_LA_DISPLAY_0C,
- TEGRA_LA_DISPLAY_1B,
+ TEGRA_LA_DISPLAY_1B, /* T30 specific */
TEGRA_LA_DISPLAY_HC,
TEGRA_LA_DISPLAY_0AB,
TEGRA_LA_DISPLAY_0BB,
TEGRA_LA_DISPLAY_0CB,
- TEGRA_LA_DISPLAY_1BB,
+ TEGRA_LA_DISPLAY_1BB, /* T30 specific */
TEGRA_LA_DISPLAY_HCB,
TEGRA_LA_EPPUP,
TEGRA_LA_EPPU,
@@ -50,27 +50,27 @@ enum tegra_la_id {
TEGRA_LA_MPCOREW,
TEGRA_LA_MPCORE_LPR,
TEGRA_LA_MPCORE_LPW,
- TEGRA_LA_MPE_UNIFBR,
- TEGRA_LA_MPE_IPRED,
- TEGRA_LA_MPE_AMEMRD,
- TEGRA_LA_MPE_CSRD,
- TEGRA_LA_MPE_UNIFBW,
- TEGRA_LA_MPE_CSWR,
+ TEGRA_LA_MPE_UNIFBR, /* T30 specific */
+ TEGRA_LA_MPE_IPRED, /* T30 specific */
+ TEGRA_LA_MPE_AMEMRD, /* T30 specific */
+ TEGRA_LA_MPE_CSRD, /* T30 specific */
+ TEGRA_LA_MPE_UNIFBW, /* T30 specific */
+ TEGRA_LA_MPE_CSWR, /* T30 specific */
TEGRA_LA_FDCDRD,
TEGRA_LA_IDXSRD,
TEGRA_LA_TEXSRD,
TEGRA_LA_FDCDWR,
TEGRA_LA_FDCDRD2,
- TEGRA_LA_IDXSRD2,
- TEGRA_LA_TEXSRD2,
+ TEGRA_LA_IDXSRD2, /* T30 specific */
+ TEGRA_LA_TEXSRD2, /* T30 specific */
TEGRA_LA_FDCDWR2,
TEGRA_LA_PPCS_AHBDMAR,
TEGRA_LA_PPCS_AHBSLVR,
TEGRA_LA_PPCS_AHBDMAW,
TEGRA_LA_PPCS_AHBSLVW,
TEGRA_LA_PTCR,
- TEGRA_LA_SATAR,
- TEGRA_LA_SATAW,
+ TEGRA_LA_SATAR, /* T30 specific */
+ TEGRA_LA_SATAW, /* T30 specific */
TEGRA_LA_VDE_BSEVR,
TEGRA_LA_VDE_MBER,
TEGRA_LA_VDE_MCER,
@@ -79,11 +79,12 @@ enum tegra_la_id {
TEGRA_LA_VDE_DBGW,
TEGRA_LA_VDE_MBEW,
TEGRA_LA_VDE_TPMW,
- TEGRA_LA_VI_RUV,
+ TEGRA_LA_VI_RUV, /* T30 specific */
TEGRA_LA_VI_WSB,
TEGRA_LA_VI_WU,
TEGRA_LA_VI_WV,
TEGRA_LA_VI_WY,
+
TEGRA_LA_MAX_ID
};
@@ -106,6 +107,12 @@ static inline void tegra_disable_latency_scaling(enum tegra_la_id id)
{
return;
}
+
+static inline void tegra_latency_allowance_update_tick_length(
+ unsigned int new_ns_per_tick)
+{
+ return;
+}
#else
int tegra_set_latency_allowance(enum tegra_la_id id,
unsigned int bandwidth_in_mbps);
@@ -116,6 +123,7 @@ int tegra_enable_latency_scaling(enum tegra_la_id id,
unsigned int threshold_high);
void tegra_disable_latency_scaling(enum tegra_la_id id);
+void tegra_latency_allowance_update_tick_length(unsigned int new_ns_per_tick);
#endif
#endif /* _MACH_TEGRA_LATENCY_ALLOWANCE_H_ */
diff --git a/arch/arm/mach-tegra/include/mach/tegra-bb-power.h b/arch/arm/mach-tegra/include/mach/tegra-bb-power.h
index e0b7e3de326f..96e36116f04f 100644
--- a/arch/arm/mach-tegra/include/mach/tegra-bb-power.h
+++ b/arch/arm/mach-tegra/include/mach/tegra-bb-power.h
@@ -50,7 +50,7 @@ union tegra_bb_gpio_id {
};
typedef struct platform_device* (*ehci_register_cb)(void);
-typedef void (*ehci_unregister_cb)(struct platform_device *);
+typedef void (*ehci_unregister_cb)(struct platform_device **);
struct tegra_bb_pdata {
union tegra_bb_gpio_id *id;
diff --git a/arch/arm/mach-tegra/include/mach/tegra_asoc_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_asoc_pdata.h
index fff2fcc68269..7aada6940b39 100644
--- a/arch/arm/mach-tegra/include/mach/tegra_asoc_pdata.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_asoc_pdata.h
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/include/mach/tegra_asoc_pdata.h
*
- * Copyright 2012 NVIDIA, 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
@@ -25,20 +25,23 @@
#define TEGRA_DAIFMT_RIGHT_J 3
#define TEGRA_DAIFMT_LEFT_J 4
-struct baseband_config {
+struct i2s_config {
+ int audio_port_id;
+ int is_i2s_master;
+ int i2s_mode;
+ int sample_size;
int rate;
int channels;
- int bit_format;
- int is_master;
};
struct tegra_asoc_platform_data {
+ const char *codec_name;
+ const char *codec_dai_name;
int gpio_spkr_en;
int gpio_hp_det;
int gpio_hp_mute;
int gpio_int_mic_en;
int gpio_ext_mic_en;
unsigned int debounce_time_hp;
- int audio_port_id[NUM_I2S_DEVICES];
- struct baseband_config baseband_param;
+ struct i2s_config i2s_param[NUM_I2S_DEVICES];
};
diff --git a/arch/arm/mach-tegra/include/mach/tegra_e1853_pdata.h b/arch/arm/mach-tegra/include/mach/tegra_e1853_pdata.h
new file mode 100644
index 000000000000..633f04855e6e
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/tegra_e1853_pdata.h
@@ -0,0 +1,55 @@
+/*
+ * arch/arm/mach-tegra/include/mach/tegra_e1853_pdata.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/>.
+ *
+ */
+
+#ifndef __MACH_TEGRA_E1853_PDATA_H
+#define __MACH_TEGRA_E1853_PDATA_H
+
+#define NUM_AUDIO_CONTROLLERS 4
+
+/* data format supported */
+enum i2s_data_format {
+ format_i2s = 0x1,
+ format_dsp = 0x2,
+ format_rjm = 0x4,
+ format_ljm = 0x8,
+ format_tdm = 0x10
+};
+
+struct codec_info_s {
+ /* Name of the Codec Dai on the system */
+ char *codec_dai_name;
+ /* Name of the I2S controller dai its connected to */
+ 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_e1853_platform_data {
+ struct codec_info_s codec_info[NUM_AUDIO_CONTROLLERS];
+};
+#endif
diff --git a/arch/arm/mach-tegra/iovmm.c b/arch/arm/mach-tegra/iovmm.c
index 86a92aec2d28..488c6a6fc828 100644
--- a/arch/arm/mach-tegra/iovmm.c
+++ b/arch/arm/mach-tegra/iovmm.c
@@ -255,11 +255,13 @@ static struct tegra_iovmm_block *iovmm_split_free_block(
struct tegra_iovmm_block *rem;
struct tegra_iovmm_block *b;
+ spin_unlock(&domain->block_lock);
rem = kmem_cache_zalloc(iovmm_cache, GFP_KERNEL);
+ spin_lock(&domain->block_lock);
+
if (!rem)
return NULL;
- spin_lock(&domain->block_lock);
p = &domain->free_blocks.rb_node;
rem->start = block->start + size;
@@ -344,7 +346,6 @@ static struct tegra_iovmm_block *iovmm_alloc_block(
simalign = SIMALIGN(best, align);
if (DO_SPLIT(simalign)) {
iovmm_block_splitting = 1;
- spin_unlock(&domain->block_lock);
/* Split off misalignment */
b = best;
@@ -365,7 +366,6 @@ static struct tegra_iovmm_block *iovmm_alloc_block(
if (DO_SPLIT((best->start + best->length) - iovmm_end(best))) {
iovmm_block_splitting = 1;
- spin_unlock(&domain->block_lock);
/* Split off excess */
(void)iovmm_split_free_block(domain, best, size + simalign);
@@ -415,7 +415,6 @@ static struct tegra_iovmm_block *iovmm_allocate_vm(
/* split the mem before iovm_start. */
if (DO_SPLIT(iovm_start - best->start)) {
iovmm_block_splitting = 1;
- spin_unlock(&domain->block_lock);
best = iovmm_split_free_block(domain, best,
(iovm_start - best->start));
}
@@ -435,7 +434,6 @@ static struct tegra_iovmm_block *iovmm_allocate_vm(
/* split the mem after iovm_start+size. */
if (DO_SPLIT(best->start + best->length - iovmm_end(best))) {
iovmm_block_splitting = 1;
- spin_unlock(&domain->block_lock);
(void)iovmm_split_free_block(domain, best,
(iovmm_start(best) - best->start + size));
}
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 278912486f40..4f34b87d8f36 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -196,6 +196,12 @@ static int tegra_legacy_irq_suspend(void)
/* disable COP interrupts */
writel(~0, ictlr + ICTLR_COP_IER_CLR);
+
+ /* disable CPU interrupts */
+ writel(~0, ictlr + ICTLR_CPU_IER_CLR);
+
+ /* enable lp1 wake sources */
+ writel(ictlr_wake_mask[i], ictlr + ICTLR_CPU_IER_SET);
}
local_irq_restore(flags);
diff --git a/arch/arm/mach-tegra/la_priv_common.h b/arch/arm/mach-tegra/la_priv_common.h
new file mode 100644
index 000000000000..5b487e5970c5
--- /dev/null
+++ b/arch/arm/mach-tegra/la_priv_common.h
@@ -0,0 +1,71 @@
+/*
+ * arch/arm/mach-tegra/la_priv_common.h
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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_LA_PRIV_H_
+#define _MACH_TEGRA_LA_PRIV_H_
+
+/* maximum valid value for latency allowance */
+#define MC_LA_MAX_VALUE 255
+
+#define MC_RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_MC_BASE) + (MC_##r))
+#define RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_MC_BASE) + (MC_LA_##r))
+
+#define MASK(x) \
+ ((0xFFFFFFFFUL >> (31 - (1 ? x) + (0 ? x))) << (0 ? x))
+#define SHIFT(x) \
+ (0 ? x)
+#define ID(id) \
+ TEGRA_LA_##id
+
+#define LA_INFO(f, e, a, r, id, ss) \
+{f, e, RA(a), MASK(r), SHIFT(r), ID(id), __stringify(id), ss}
+
+struct la_client_info {
+ unsigned int fifo_size_in_atoms;
+ unsigned int expiration_in_ns; /* worst case expiration value */
+ unsigned long reg_addr;
+ unsigned long mask;
+ unsigned long shift;
+ enum tegra_la_id id;
+ char *name;
+ bool scaling_supported;
+};
+
+struct la_scaling_info {
+ unsigned int threshold_low;
+ unsigned int threshold_mid;
+ unsigned int threshold_high;
+ int scaling_ref_count;
+ int actual_la_to_set;
+ int la_set;
+};
+
+struct la_scaling_reg_info {
+ enum tegra_la_id id;
+ unsigned int tl_reg_addr;
+ unsigned int tl_mask;
+ unsigned int tl_shift;
+ unsigned int tm_reg_addr;
+ unsigned int tm_mask;
+ unsigned int tm_shift;
+ unsigned int th_reg_addr;
+ unsigned int th_mask;
+ unsigned int th_shift;
+};
+
+#endif /* _MACH_TEGRA_LA_PRIV_H_ */
diff --git a/arch/arm/mach-tegra/latency_allowance.c b/arch/arm/mach-tegra/latency_allowance.c
index 7698ba39f4ca..86ab179e4646 100644
--- a/arch/arm/mach-tegra/latency_allowance.c
+++ b/arch/arm/mach-tegra/latency_allowance.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/latency_allowance.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
@@ -29,68 +29,8 @@
#include <mach/iomap.h>
#include <mach/io.h>
#include <mach/latency_allowance.h>
-
-#define MC_ARB_OVERRIDE 0xe8
-#define GLOBAL_LATENCY_SCALING_ENABLE_BIT 7
-
-#define MC_LA_AFI_0 0x2e0
-#define MC_LA_AVPC_ARM7_0 0x2e4
-#define MC_LA_DC_0 0x2e8
-#define MC_LA_DC_1 0x2ec
-#define MC_LA_DC_2 0x2f0
-#define MC_LA_DCB_0 0x2f4
-#define MC_LA_DCB_1 0x2f8
-#define MC_LA_DCB_2 0x2fc
-#define MC_LA_EPP_0 0x300
-#define MC_LA_EPP_1 0x304
-#define MC_LA_G2_0 0x308
-#define MC_LA_G2_1 0x30c
-#define MC_LA_HC_0 0x310
-#define MC_LA_HC_1 0x314
-#define MC_LA_HDA_0 0x318
-#define MC_LA_ISP_0 0x31C
-#define MC_LA_MPCORE_0 0x320
-#define MC_LA_MPCORELP_0 0x324
-#define MC_LA_MPE_0 0x328
-#define MC_LA_MPE_1 0x32c
-#define MC_LA_MPE_2 0x330
-#define MC_LA_NV_0 0x334
-#define MC_LA_NV_1 0x338
-#define MC_LA_NV2_0 0x33c
-#define MC_LA_NV2_1 0x340
-#define MC_LA_PPCS_0 0x344
-#define MC_LA_PPCS_1 0x348
-#define MC_LA_PTC_0 0x34c
-#define MC_LA_SATA_0 0x350
-#define MC_LA_VDE_0 0x354
-#define MC_LA_VDE_1 0x358
-#define MC_LA_VDE_2 0x35c
-#define MC_LA_VDE_3 0x360
-#define MC_LA_VI_0 0x364
-#define MC_LA_VI_1 0x368
-#define MC_LA_VI_2 0x36c
-
-#define DS_DISP_MCCIF_DISPLAY0A_HYST (0x481 * 4)
-#define DS_DISP_MCCIF_DISPLAY0B_HYST (0x482 * 4)
-#define DS_DISP_MCCIF_DISPLAY0C_HYST (0x483 * 4)
-#define DS_DISP_MCCIF_DISPLAY1B_HYST (0x484 * 4)
-
-#define DS_DISP_MCCIF_DISPLAY0AB_HYST (0x481 * 4)
-#define DS_DISP_MCCIF_DISPLAY0BB_HYST (0x482 * 4)
-#define DS_DISP_MCCIF_DISPLAY0CB_HYST (0x483 * 4)
-#define DS_DISP_MCCIF_DISPLAY1BB_HYST (0x484 * 4)
-
-#define VI_MCCIF_VIWSB_HYST (0x9a * 4)
-#define VI_MCCIF_VIWU_HYST (0x9b * 4)
-#define VI_MCCIF_VIWV_HYST (0x9c * 4)
-#define VI_MCCIF_VIWY_HYST (0x9d * 4)
-
-#define VI_TIMEOUT_WOCAL_VI (0x70 * 4)
-#define VI_RESERVE_3 (0x97 * 4)
-#define VI_RESERVE_4 (0x98 * 4)
-
-/* maximum valid value for latency allowance */
-#define MC_LA_MAX_VALUE 255
+#include "la_priv_common.h"
+#include "tegra3_la_priv.h"
#define ENABLE_LA_DEBUG 0
#define TEST_LA_CODE 0
@@ -100,210 +40,22 @@
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__); \
}
-static struct dentry *latency_debug_dir;
-
-struct la_client_info {
- unsigned int fifo_size_in_atoms;
- unsigned int expiration_in_ns; /* worst case expiration value */
- unsigned long reg_addr;
- unsigned long mask;
- unsigned long shift;
- enum tegra_la_id id;
- char *name;
- bool scaling_supported;
-};
+/* Bug 995270 */
+#define HACK_LA_FIFO 1
+static struct dentry *latency_debug_dir;
static DEFINE_SPINLOCK(safety_lock);
-
-static const int ns_per_tick = 30;
-/* fifo atom size in bytes for non-fdc clients*/
-static const int normal_atom_size = 16;
-/* fifo atom size in bytes for fdc clients*/
-static const int fdc_atom_size = 32;
-
-#define MC_RA(r) \
- ((u32)IO_ADDRESS(TEGRA_MC_BASE) + (MC_##r))
-#define RA(r) \
- ((u32)IO_ADDRESS(TEGRA_MC_BASE) + (MC_LA_##r))
-
-#define MASK(x) \
- ((0xFFFFFFFFUL >> (31 - (1 ? x) + (0 ? x))) << (0 ? x))
-#define SHIFT(x) \
- (0 ? x)
-#define ID(id) \
- TEGRA_LA_##id
-
-#define LA_INFO(f, e, a, r, id, ss) \
-{f, e, RA(a), MASK(r), SHIFT(r), ID(id), __stringify(id), ss}
-
-/*
- * The rule for getting the fifo_size_in_atoms is:
- * 1.If REORDER_DEPTH exists, use it(default is overridden).
- * 2.Else if (write_client) use RFIFO_DEPTH.
- * 3.Else (read client) use RDFIFO_DEPTH.
- * Refer to project.h file.
- */
-struct la_client_info la_info[] = {
- LA_INFO(32, 150, AFI_0, 7 : 0, AFIR, false),
- LA_INFO(32, 150, AFI_0, 23 : 16, AFIW, false),
- LA_INFO(2, 150, AVPC_ARM7_0, 7 : 0, AVPC_ARM7R, false),
- LA_INFO(2, 150, AVPC_ARM7_0, 23 : 16, AVPC_ARM7W, false),
- LA_INFO(128, 1050, DC_0, 7 : 0, DISPLAY_0A, true),
- LA_INFO(64, 1050, DC_0, 23 : 16, DISPLAY_0B, true),
- LA_INFO(128, 1050, DC_1, 7 : 0, DISPLAY_0C, true),
- LA_INFO(64, 1050, DC_1, 23 : 16, DISPLAY_1B, true),
- LA_INFO(2, 1050, DC_2, 7 : 0, DISPLAY_HC, false),
- LA_INFO(128, 1050, DCB_0, 7 : 0, DISPLAY_0AB, true),
- LA_INFO(64, 1050, DCB_0, 23 : 16, DISPLAY_0BB, true),
- LA_INFO(128, 1050, DCB_1, 7 : 0, DISPLAY_0CB, true),
- LA_INFO(64, 1050, DCB_1, 23 : 16, DISPLAY_1BB, true),
- LA_INFO(2, 1050, DCB_2, 7 : 0, DISPLAY_HCB, false),
- LA_INFO(8, 150, EPP_0, 7 : 0, EPPUP, false),
- LA_INFO(64, 150, EPP_0, 23 : 16, EPPU, false),
- LA_INFO(64, 150, EPP_1, 7 : 0, EPPV, false),
- LA_INFO(64, 150, EPP_1, 23 : 16, EPPY, false),
- LA_INFO(64, 150, G2_0, 7 : 0, G2PR, false),
- LA_INFO(64, 150, G2_0, 23 : 16, G2SR, false),
- LA_INFO(48, 150, G2_1, 7 : 0, G2DR, false),
- LA_INFO(128, 150, G2_1, 23 : 16, G2DW, false),
- LA_INFO(16, 150, HC_0, 7 : 0, HOST1X_DMAR, false),
- LA_INFO(8, 150, HC_0, 23 : 16, HOST1XR, false),
- LA_INFO(32, 150, HC_1, 7 : 0, HOST1XW, false),
- LA_INFO(16, 150, HDA_0, 7 : 0, HDAR, false),
- LA_INFO(16, 150, HDA_0, 23 : 16, HDAW, false),
- LA_INFO(64, 150, ISP_0, 7 : 0, ISPW, false),
- LA_INFO(14, 150, MPCORE_0, 7 : 0, MPCORER, false),
- LA_INFO(24, 150, MPCORE_0, 23 : 16, MPCOREW, false),
- LA_INFO(14, 150, MPCORELP_0, 7 : 0, MPCORE_LPR, false),
- LA_INFO(24, 150, MPCORELP_0, 23 : 16, MPCORE_LPW, false),
- LA_INFO(8, 150, MPE_0, 7 : 0, MPE_UNIFBR, false),
- LA_INFO(2, 150, MPE_0, 23 : 16, MPE_IPRED, false),
- LA_INFO(64, 150, MPE_1, 7 : 0, MPE_AMEMRD, false),
- LA_INFO(8, 150, MPE_1, 23 : 16, MPE_CSRD, false),
- LA_INFO(8, 150, MPE_2, 7 : 0, MPE_UNIFBW, false),
- LA_INFO(8, 150, MPE_2, 23 : 16, MPE_CSWR, false),
- LA_INFO(48, 150, NV_0, 7 : 0, FDCDRD, false),
- LA_INFO(64, 150, NV_0, 23 : 16, IDXSRD, false),
- LA_INFO(64, 150, NV_1, 7 : 0, TEXSRD, false),
- LA_INFO(48, 150, NV_1, 23 : 16, FDCDWR, false),
- LA_INFO(48, 150, NV2_0, 7 : 0, FDCDRD2, false),
- LA_INFO(64, 150, NV2_0, 23 : 16, IDXSRD2, false),
- LA_INFO(64, 150, NV2_1, 7 : 0, TEXSRD2, false),
- LA_INFO(48, 150, NV2_1, 23 : 16, FDCDWR2, false),
- LA_INFO(2, 150, PPCS_0, 7 : 0, PPCS_AHBDMAR, false),
- LA_INFO(8, 150, PPCS_0, 23 : 16, PPCS_AHBSLVR, false),
- LA_INFO(2, 150, PPCS_1, 7 : 0, PPCS_AHBDMAW, false),
- LA_INFO(4, 150, PPCS_1, 23 : 16, PPCS_AHBSLVW, false),
- LA_INFO(2, 150, PTC_0, 7 : 0, PTCR, false),
- LA_INFO(32, 150, SATA_0, 7 : 0, SATAR, false),
- LA_INFO(32, 150, SATA_0, 23 : 16, SATAW, false),
- LA_INFO(8, 150, VDE_0, 7 : 0, VDE_BSEVR, false),
- LA_INFO(4, 150, VDE_0, 23 : 16, VDE_MBER, false),
- LA_INFO(16, 150, VDE_1, 7 : 0, VDE_MCER, false),
- LA_INFO(16, 150, VDE_1, 23 : 16, VDE_TPER, false),
- LA_INFO(4, 150, VDE_2, 7 : 0, VDE_BSEVW, false),
- LA_INFO(16, 150, VDE_2, 23 : 16, VDE_DBGW, false),
- LA_INFO(2, 150, VDE_3, 7 : 0, VDE_MBEW, false),
- LA_INFO(16, 150, VDE_3, 23 : 16, VDE_TPMW, false),
- LA_INFO(8, 1050, VI_0, 7 : 0, VI_RUV, false),
- LA_INFO(64, 1050, VI_0, 23 : 16, VI_WSB, true),
- LA_INFO(64, 1050, VI_1, 7 : 0, VI_WU, true),
- LA_INFO(64, 1050, VI_1, 23 : 16, VI_WV, true),
- LA_INFO(64, 1050, VI_2, 7 : 0, VI_WY, true),
-
-/* end of list. */
- LA_INFO(0, 0, AFI_0, 0 : 0, MAX_ID, false)
-};
-
-struct la_scaling_info {
- unsigned int threshold_low;
- unsigned int threshold_mid;
- unsigned int threshold_high;
- int scaling_ref_count;
- int actual_la_to_set;
- int la_set;
-};
-
-struct la_scaling_reg_info {
- enum tegra_la_id id;
- unsigned int tl_reg_addr;
- unsigned int tl_mask;
- unsigned int tl_shift;
- unsigned int tm_reg_addr;
- unsigned int tm_mask;
- unsigned int tm_shift;
- unsigned int th_reg_addr;
- unsigned int th_mask;
- unsigned int th_shift;
-};
-
-#define DISP1_RA(r) \
- ((u32)IO_ADDRESS(TEGRA_DISPLAY_BASE) + DS_DISP_MCCIF_##r##_HYST)
-#define DISP2_RA(r) \
- ((u32)IO_ADDRESS(TEGRA_DISPLAY2_BASE) + DS_DISP_MCCIF_##r##_HYST)
-
-#define DISP_SCALING_REG_INFO(id, r, ra) \
- { \
- ID(id), \
- ra(r), MASK(15 : 8), SHIFT(15 : 8), \
- ra(r), MASK(23 : 16), SHIFT(15 : 8), \
- ra(r), MASK(7 : 0), SHIFT(15 : 8) \
- }
-
-struct la_scaling_reg_info disp_info[] = {
- DISP_SCALING_REG_INFO(DISPLAY_0A, DISPLAY0A, DISP1_RA),
- DISP_SCALING_REG_INFO(DISPLAY_0B, DISPLAY0B, DISP1_RA),
- DISP_SCALING_REG_INFO(DISPLAY_0C, DISPLAY0C, DISP1_RA),
- DISP_SCALING_REG_INFO(DISPLAY_1B, DISPLAY1B, DISP1_RA),
- DISP_SCALING_REG_INFO(MAX_ID, DISPLAY1B, DISP1_RA), /*dummy entry*/
- DISP_SCALING_REG_INFO(DISPLAY_0AB, DISPLAY0AB, DISP2_RA),
- DISP_SCALING_REG_INFO(DISPLAY_0BB, DISPLAY0BB, DISP2_RA),
- DISP_SCALING_REG_INFO(DISPLAY_0CB, DISPLAY0CB, DISP2_RA),
- DISP_SCALING_REG_INFO(DISPLAY_1BB, DISPLAY1BB, DISP2_RA),
-};
-
-#define VI_TH_RA(r) \
- ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_MCCIF_##r##_HYST)
-#define VI_TM_RA(r) \
- ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_TIMEOUT_WOCAL_VI)
-#define VI_TL_RA(r) \
- ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_RESERVE_##r)
-
-struct la_scaling_reg_info vi_info[] = {
- {
- ID(VI_WSB),
- VI_TL_RA(4), MASK(7 : 0), SHIFT(7 : 0),
- VI_TM_RA(0), MASK(7 : 0), SHIFT(7 : 0),
- VI_TH_RA(VIWSB), MASK(7 : 0), SHIFT(7 : 0)
- },
- {
- ID(VI_WU),
- VI_TL_RA(3), MASK(15 : 8), SHIFT(15 : 8),
- VI_TM_RA(0), MASK(15 : 8), SHIFT(15 : 8),
- VI_TH_RA(VIWU), MASK(7 : 0), SHIFT(7 : 0)
- },
- {
- ID(VI_WV),
- VI_TL_RA(3), MASK(7 : 0), SHIFT(7 : 0),
- VI_TM_RA(0), MASK(23 : 16), SHIFT(23 : 16),
- VI_TH_RA(VIWV), MASK(7 : 0), SHIFT(7 : 0)
- },
- {
- ID(VI_WY),
- VI_TL_RA(4), MASK(15 : 8), SHIFT(15 : 8),
- VI_TM_RA(0), MASK(31 : 24), SHIFT(31 : 24),
- VI_TH_RA(VIWY), MASK(7 : 0), SHIFT(7 : 0)
- }
-};
-
+static unsigned short id_to_index[ID(MAX_ID) + 1];
static struct la_scaling_info scaling_info[TEGRA_LA_MAX_ID];
static int la_scaling_enable_count;
#define VALIDATE_ID(id) \
do { \
- if (id >= TEGRA_LA_MAX_ID) \
+ if (id >= TEGRA_LA_MAX_ID || id_to_index[id] == 0xFFFF) { \
+ pr_err("%s: invalid Id=%d", __func__, id); \
return -EINVAL; \
- BUG_ON(la_info[id].id != id); \
+ } \
+ BUG_ON(la_info_array[id_to_index[id]].id != id); \
} while (0)
#define VALIDATE_BW(bw_in_mbps) \
@@ -327,20 +79,22 @@ static void set_thresholds(struct la_scaling_reg_info *info,
unsigned int thresh_mid;
unsigned int thresh_high;
int la_set;
+ int idx = id_to_index[id];
- reg_read = readl(la_info[id].reg_addr);
- la_set = (reg_read & la_info[id].mask) >> la_info[id].shift;
+ reg_read = readl(la_info_array[idx].reg_addr);
+ la_set = (reg_read & la_info_array[idx].mask) >>
+ la_info_array[idx].shift;
/* la should be set before enabling scaling. */
- BUG_ON(la_set != scaling_info[id].la_set);
+ BUG_ON(la_set != scaling_info[idx].la_set);
- thresh_low = (scaling_info[id].threshold_low * la_set) / 100;
- thresh_mid = (scaling_info[id].threshold_mid * la_set) / 100;
- thresh_high = (scaling_info[id].threshold_high * la_set) / 100;
+ thresh_low = (scaling_info[idx].threshold_low * la_set) / 100;
+ thresh_mid = (scaling_info[idx].threshold_mid * la_set) / 100;
+ thresh_high = (scaling_info[idx].threshold_high * la_set) / 100;
la_debug("%s: la_set=%d, thresh_low=%d(%d%%), thresh_mid=%d(%d%%),"
" thresh_high=%d(%d%%) ", __func__, la_set,
- thresh_low, scaling_info[id].threshold_low,
- thresh_mid, scaling_info[id].threshold_mid,
- thresh_high, scaling_info[id].threshold_high);
+ thresh_low, scaling_info[idx].threshold_low,
+ thresh_mid, scaling_info[idx].threshold_mid,
+ thresh_high, scaling_info[idx].threshold_high);
reg_read = readl(info->tl_reg_addr);
reg_write = (reg_read & ~info->tl_mask) |
@@ -384,42 +138,45 @@ int tegra_set_latency_allowance(enum tegra_la_id id,
int la_to_set;
unsigned long reg_read;
unsigned long reg_write;
+ unsigned int fifo_size_in_atoms;
int bytes_per_atom = normal_atom_size;
+ const int fifo_scale = 4; /* 25% of the FIFO */
struct la_client_info *ci;
+ int idx = id_to_index[id];
VALIDATE_ID(id);
VALIDATE_BW(bandwidth_in_mbps);
- if (id == ID(FDCDRD) || id == ID(FDCDWR) ||
- id == ID(FDCDRD2) || id == ID(FDCDWR2))
- bytes_per_atom = fdc_atom_size;
- ci = &la_info[id];
+ ci = &la_info_array[idx];
+ fifo_size_in_atoms = ci->fifo_size_in_atoms;
+
+#if HACK_LA_FIFO
+ /* pretend that our FIFO is only as deep as the lowest fullness
+ * we expect to see */
+ if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_HCB))
+ fifo_size_in_atoms /= fifo_scale;
+#endif
if (bandwidth_in_mbps == 0) {
la_to_set = MC_LA_MAX_VALUE;
} else {
- ideal_la = (ci->fifo_size_in_atoms * bytes_per_atom * 1000) /
+ ideal_la = (fifo_size_in_atoms * bytes_per_atom * 1000) /
(bandwidth_in_mbps * ns_per_tick);
la_to_set = ideal_la - (ci->expiration_in_ns/ns_per_tick) - 1;
}
- la_debug("\n%s:id=%d,bw=%dmbps, la_to_set=%d",
- __func__, id, bandwidth_in_mbps, la_to_set);
+ la_debug("\n%s:id=%d,idx=%d, bw=%dmbps, la_to_set=%d",
+ __func__, id, idx, bandwidth_in_mbps, la_to_set);
la_to_set = (la_to_set < 0) ? 0 : la_to_set;
la_to_set = (la_to_set > MC_LA_MAX_VALUE) ? MC_LA_MAX_VALUE : la_to_set;
- scaling_info[id].actual_la_to_set = la_to_set;
-
- /* until display can use latency allowance scaling, use a more
- * aggressive LA setting. Bug 862709 */
- if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_HCB))
- la_to_set /= 3;
+ scaling_info[idx].actual_la_to_set = la_to_set;
spin_lock(&safety_lock);
reg_read = readl(ci->reg_addr);
reg_write = (reg_read & ~ci->mask) |
(la_to_set << ci->shift);
writel(reg_write, ci->reg_addr);
- scaling_info[id].la_set = la_to_set;
+ scaling_info[idx].la_set = la_to_set;
la_debug("reg_addr=0x%x, read=0x%x, write=0x%x",
(u32)ci->reg_addr, (u32)reg_read, (u32)reg_write);
spin_unlock(&safety_lock);
@@ -442,21 +199,22 @@ int tegra_enable_latency_scaling(enum tegra_la_id id,
{
unsigned long reg;
unsigned long scaling_enable_reg = MC_RA(ARB_OVERRIDE);
+ int idx = id_to_index[id];
VALIDATE_ID(id);
VALIDATE_THRESHOLDS(threshold_low, threshold_mid, threshold_high);
- if (la_info[id].scaling_supported == false)
+ if (la_info_array[idx].scaling_supported == false)
goto exit;
spin_lock(&safety_lock);
la_debug("\n%s: id=%d, tl=%d, tm=%d, th=%d", __func__,
id, threshold_low, threshold_mid, threshold_high);
- scaling_info[id].threshold_low = threshold_low;
- scaling_info[id].threshold_mid = threshold_mid;
- scaling_info[id].threshold_high = threshold_high;
- scaling_info[id].scaling_ref_count++;
+ scaling_info[idx].threshold_low = threshold_low;
+ scaling_info[idx].threshold_mid = threshold_mid;
+ scaling_info[idx].threshold_high = threshold_high;
+ scaling_info[idx].scaling_ref_count++;
if (id >= ID(DISPLAY_0A) && id <= ID(DISPLAY_1BB))
set_disp_latency_thresholds(id);
@@ -477,17 +235,18 @@ void tegra_disable_latency_scaling(enum tegra_la_id id)
{
unsigned long reg;
unsigned long scaling_enable_reg = MC_RA(ARB_OVERRIDE);
+ int idx;
- if (id >= TEGRA_LA_MAX_ID)
- return;
- BUG_ON(la_info[id].id != id);
+ BUG_ON(id >= TEGRA_LA_MAX_ID);
+ idx = id_to_index[id];
+ BUG_ON(la_info_array[idx].id != id);
- if (la_info[id].scaling_supported == false)
+ if (la_info_array[idx].scaling_supported == false)
return;
spin_lock(&safety_lock);
la_debug("\n%s: id=%d", __func__, id);
- scaling_info[id].scaling_ref_count--;
- BUG_ON(scaling_info[id].scaling_ref_count < 0);
+ scaling_info[idx].scaling_ref_count--;
+ BUG_ON(scaling_info[idx].scaling_ref_count < 0);
if (!--la_scaling_enable_count) {
reg = readl(scaling_enable_reg);
@@ -498,19 +257,50 @@ void tegra_disable_latency_scaling(enum tegra_la_id id)
spin_unlock(&safety_lock);
}
+void tegra_latency_allowance_update_tick_length(unsigned int new_ns_per_tick)
+{
+ int i = 0;
+ int la;
+ unsigned long reg_read;
+ unsigned long reg_write;
+ unsigned long scale_factor = new_ns_per_tick / ns_per_tick;
+
+ if (scale_factor > 1) {
+ spin_lock(&safety_lock);
+ ns_per_tick = new_ns_per_tick;
+ for (i = 0; i < ARRAY_SIZE(la_info_array) - 1; i++) {
+ reg_read = readl(la_info_array[i].reg_addr);
+ la = ((reg_read & la_info_array[i].mask) >>
+ la_info_array[i].shift) / scale_factor;
+
+ reg_write = (reg_read & ~la_info_array[i].mask) |
+ (la << la_info_array[i].shift);
+ writel(reg_write, la_info_array[i].reg_addr);
+ scaling_info[i].la_set = la;
+ }
+ spin_unlock(&safety_lock);
+
+ /* Re-scale G2PR, G2SR, G2DR, G2DW with updated ns_per_tick */
+ tegra_set_latency_allowance(TEGRA_LA_G2PR, 20);
+ tegra_set_latency_allowance(TEGRA_LA_G2SR, 20);
+ tegra_set_latency_allowance(TEGRA_LA_G2DR, 20);
+ tegra_set_latency_allowance(TEGRA_LA_G2DW, 20);
+ }
+}
+
static int la_regs_show(struct seq_file *s, void *unused)
{
unsigned i;
unsigned long la;
/* iterate the list, but don't print MAX_ID */
- for (i = 0; i < ARRAY_SIZE(la_info) - 1; i++) {
- la = (readl(la_info[i].reg_addr) & la_info[i].mask)
- >> la_info[i].shift;
- seq_printf(s, "%-16s: %4lu\n", la_info[i].name, la);
+ for (i = 0; i < ARRAY_SIZE(la_info_array) - 1; i++) {
+ la = (readl(la_info_array[i].reg_addr) & la_info_array[i].mask)
+ >> la_info_array[i].shift;
+ seq_printf(s, "%-16s: %4lu\n", la_info_array[i].name, la);
}
- return 0;
+ return 0;
}
static int dbg_la_regs_open(struct inode *inode, struct file *file)
@@ -542,7 +332,13 @@ late_initcall(tegra_latency_allowance_debugfs_init);
static int __init tegra_latency_allowance_init(void)
{
+ unsigned int i;
+
la_scaling_enable_count = 0;
+ memset(&id_to_index[0], 0xFF, sizeof(id_to_index));
+
+ for (i = 0; i < ARRAY_SIZE(la_info_array); i++)
+ id_to_index[la_info_array[i].id] = i;
tegra_set_latency_allowance(TEGRA_LA_G2PR, 20);
tegra_set_latency_allowance(TEGRA_LA_G2SR, 20);
@@ -554,12 +350,19 @@ static int __init tegra_latency_allowance_init(void)
core_initcall(tegra_latency_allowance_init);
#if TEST_LA_CODE
+#define PRINT_ID_IDX_MAPPING 0
static int __init test_la(void)
{
+ int i;
int err;
enum tegra_la_id id = 0;
int repeat_count = 5;
+#if PRINT_ID_IDX_MAPPING
+ for (i = 0; i < ID(MAX_ID); i++)
+ pr_info("ID=0x%x, Idx=0x%x", i, id_to_index[i]);
+#endif
+
do {
for (id = 0; id < TEGRA_LA_MAX_ID; id++) {
err = tegra_set_latency_allowance(id, 200);
diff --git a/arch/arm/mach-tegra/p852/board-p852-gpio.c b/arch/arm/mach-tegra/p852/board-p852-gpio.c
index 71f568087c5d..6272d36fb849 100644
--- a/arch/arm/mach-tegra/p852/board-p852-gpio.c
+++ b/arch/arm/mach-tegra/p852/board-p852-gpio.c
@@ -152,7 +152,6 @@ void __init p852_gpio_init(void)
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);
}
}
diff --git a/arch/arm/mach-tegra/p852/board-p852-sdhci.c b/arch/arm/mach-tegra/p852/board-p852-sdhci.c
index dc5b81fa3727..54fd42e38ab6 100644
--- a/arch/arm/mach-tegra/p852/board-p852-sdhci.c
+++ b/arch/arm/mach-tegra/p852/board-p852-sdhci.c
@@ -165,7 +165,7 @@ void __init p852_sdhci_init(void)
gpio_request(p852_sdhci_platform_data
[i].cd_gpio,
gpio_name[cd]);
- tegra_gpio_enable
+ gpio_direction_input
(p852_sdhci_platform_data[i].
cd_gpio);
}
@@ -176,7 +176,7 @@ void __init p852_sdhci_init(void)
gpio_request(p852_sdhci_platform_data
[i].wp_gpio,
gpio_name[wp]);
- tegra_gpio_enable
+ gpio_direction_input
(p852_sdhci_platform_data[i].
wp_gpio);
}
@@ -187,7 +187,7 @@ void __init p852_sdhci_init(void)
gpio_request(p852_sdhci_platform_data
[i].power_gpio,
gpio_name[pw]);
- tegra_gpio_enable
+ gpio_direction_input
(p852_sdhci_platform_data[i].
power_gpio);
}
diff --git a/arch/arm/mach-tegra/p852/board-p852.c b/arch/arm/mach-tegra/p852/board-p852.c
index 039d9db6a3a6..0382d7306f42 100644
--- a/arch/arm/mach-tegra/p852/board-p852.c
+++ b/arch/arm/mach-tegra/p852/board-p852.c
@@ -342,12 +342,10 @@ static void p852_usb_gpio_config(void)
if (has_onboard_ethernet) {
gpio_request_one(usbeth_mux_gpio, GPIOF_OUT_INIT_LOW,
"eth_ena");
- tegra_gpio_enable(usbeth_mux_gpio);
/* eth reset */
gpio_request_one(p852_eth_reset, GPIOF_OUT_INIT_LOW,
"eth_reset");
- tegra_gpio_enable(p852_eth_reset);
udelay(1);
gpio_direction_output(p852_eth_reset, 1);
@@ -432,7 +430,6 @@ void __init p852_spi_i2s_init(void)
gpio_request_one(pdata->gpio_i2s.gpio_no, GPIOF_OUT_INIT_HIGH,
"i2s_cpld_dir1");
}
- tegra_gpio_enable(pdata->gpio_i2s.gpio_no);
if (pdata->gpio_spi.active_state) {
gpio_request_one(pdata->gpio_spi.gpio_no, GPIOF_OUT_INIT_LOW,
"spi_cpld_dir2");
@@ -441,7 +438,6 @@ void __init p852_spi_i2s_init(void)
"spi_cpld_dir2");
}
- tegra_gpio_enable(pdata->gpio_spi.gpio_no);
spi_register_board_info(&tegra_spi_i2s_device, 1);
}
#endif
@@ -498,7 +494,6 @@ static void ulpi_link_platform_open(void)
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);
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index ec386a51721c..04d3a5db3f7e 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -105,6 +105,7 @@
#define AFI_CONFIGURATION 0xac
#define AFI_CONFIGURATION_EN_FPCI (1 << 0)
+#define AFI_CONFIGURATION_DFPCI_RSPPASSPW (1 << 2)
#define AFI_FPCI_ERROR_MASKS 0xb0
@@ -155,6 +156,12 @@
#define RP_VEND_XP 0x00000F00
#define RP_VEND_XP_DL_UP (1 << 30)
+#define RP_TXBA1 0x00000E1C
+#define RP_TXBA1_CM_OVER_PW_BURST_MASK (0xF << 4)
+#define RP_TXBA1_CM_OVER_PW_BURST_INIT_VAL (0x4 << 4)
+#define RP_TXBA1_PW_OVER_CM_BURST_MASK (0xF)
+#define RP_TXBA1_PW_OVER_CM_BURST_INIT_VAL (0x4)
+
#define RP_LINK_CONTROL_STATUS 0x00000090
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
@@ -300,7 +307,7 @@ struct tegra_pcie_info {
void __iomem *reg_clk_base;
void __iomem *regs;
- struct resource res_mmio;
+ struct resource *res_mmio;
int power_rails_enabled;
int pcie_power_enabled;
struct work_struct hotplug_detect;
@@ -311,20 +318,13 @@ struct tegra_pcie_info {
struct clk *pcie_xclk;
struct clk *pll_e;
struct tegra_pci_platform_data *plat_data;
-};
+}tegra_pcie;
-#define pmc_writel(value, reg) \
- __raw_writel(value, (u32)reg_pmc_base + (reg))
-#define pmc_readl(reg) \
- __raw_readl((u32)reg_pmc_base + (reg))
-
-static struct tegra_pcie_info tegra_pcie = {
- .res_mmio = {
- .name = "PCI IO",
- .start = MMIO_BASE,
- .end = MMIO_BASE + MMIO_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
+struct resource tegra_pcie_res_mmio = {
+ .name = "PCI IO",
+ .start = MMIO_BASE,
+ .end = MMIO_BASE + MMIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
};
static struct resource pcie_io_space;
@@ -639,9 +639,6 @@ static void tegra_pcie_hotplug_init(void)
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
@@ -880,8 +877,11 @@ static void tegra_pcie_enable_controller(void)
/* Take the PCIe interface module out of reset */
tegra_periph_reset_deassert(tegra_pcie.pcie_xclk);
+ /* WAR avoid hang on CPU read/write while gpu transfers in progress */
+ val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_DFPCI_RSPPASSPW;
+
/* Finally enable PCIe */
- val = afi_readl(AFI_CONFIGURATION) | AFI_CONFIGURATION_EN_FPCI;
+ val |= AFI_CONFIGURATION_EN_FPCI;
afi_writel(val, AFI_CONFIGURATION);
val = (AFI_INTR_EN_INI_SLVERR | AFI_INTR_EN_INI_DECERR |
@@ -902,8 +902,12 @@ static void tegra_pcie_enable_controller(void)
static int tegra_pcie_enable_regulators(void)
{
- if (tegra_pcie.power_rails_enabled)
+ if (tegra_pcie.power_rails_enabled) {
+ pr_debug("PCIE: Already power rails enabled");
return 0;
+ }
+ tegra_pcie.power_rails_enabled = 1;
+
if (tegra_pcie.regulator_hvdd == NULL) {
printk(KERN_INFO "PCIE.C: %s : regulator hvdd_pex\n",
__func__);
@@ -948,16 +952,17 @@ static int tegra_pcie_enable_regulators(void)
if (tegra_pcie.regulator_avdd_plle)
regulator_enable(tegra_pcie.regulator_avdd_plle);
- tegra_pcie.power_rails_enabled = 1;
-
return 0;
}
static int tegra_pcie_disable_regulators(void)
{
int err = 0;
- if (tegra_pcie.power_rails_enabled == 0)
+
+ if (tegra_pcie.power_rails_enabled == 0) {
+ pr_debug("PCIE: Already power rails disabled");
goto err_exit;
+ }
if (tegra_pcie.regulator_hvdd)
err = regulator_disable(tegra_pcie.regulator_hvdd);
if (err)
@@ -985,30 +990,92 @@ static int tegra_pcie_power_regate(void)
return clk_enable(tegra_pcie.pll_e);
}
-#ifdef CONFIG_PM
+static int tegra_pcie_map_resources(void)
+{
+ int err;
+
+ /* 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");
+ return -ENOMEM;
+ }
+
+ err = request_resource(&iomem_resource, &tegra_pcie_res_mmio);
+ if (err) {
+ pr_err("PCIE: Failed to request resources: %d\n", err);
+ return err;
+ }
+ tegra_pcie.res_mmio = &tegra_pcie_res_mmio;
+
+ /* Allocate downstream IO virtual memory */
+ tegra_pcie_io_base = ioremap_nocache(tegra_pcie_res_mmio.start,
+ resource_size(&tegra_pcie_res_mmio));
+ if (tegra_pcie_io_base == NULL) {
+ pr_err("PCIE: Failed to map IO\n");
+ return -ENOMEM;
+ }
+ return err;
+}
+
+void tegra_pcie_unmap_resources(void)
+{
+ if (tegra_pcie_io_base) {
+ iounmap(tegra_pcie_io_base);
+ tegra_pcie_io_base = 0;
+ }
+ if (tegra_pcie.res_mmio) {
+ release_resource(tegra_pcie.res_mmio);
+ tegra_pcie.res_mmio = 0;
+ }
+ if (tegra_pcie.regs) {
+ iounmap(tegra_pcie.regs);
+ tegra_pcie.regs = 0;
+ }
+}
+static int tegra_pcie_power_off(void);
+
static int tegra_pcie_power_on(void)
{
int err = 0;
- if (tegra_pcie.pcie_power_enabled)
- return 0;
+
+ if (tegra_pcie.pcie_power_enabled) {
+ pr_debug("PCIE: Already powered on");
+ goto err_exit;
+ }
+ tegra_pcie.pcie_power_enabled = 1;
+
err = tegra_pcie_enable_regulators();
- if (err)
+ if (err) {
+ pr_err("PCIE: Failed to enable regulators\n");
goto err_exit;
+ }
err = tegra_pcie_power_regate();
- if (err)
+ if (err) {
+ pr_err("PCIE: Failed to power regate\n");
+ goto err_exit;
+ }
+ err = tegra_pcie_map_resources();
+ if (err) {
+ pr_err("PCIE: Failed to map resources\n");
goto err_exit;
+ }
- tegra_pcie.pcie_power_enabled = 1;
err_exit:
+ if (err)
+ tegra_pcie_power_off();
return err;
}
-#endif
static int tegra_pcie_power_off(void)
{
int err = 0;
- if (tegra_pcie.pcie_power_enabled == 0)
- return 0;
+
+ if (tegra_pcie.pcie_power_enabled == 0) {
+ pr_debug("PCIE: Already powered off");
+ goto err_exit;
+ }
+ tegra_pcie_unmap_resources();
if (tegra_pcie.pll_e)
clk_disable(tegra_pcie.pll_e);
@@ -1047,81 +1114,42 @@ error_exit:
static void tegra_pcie_clocks_put(void)
{
- clk_put(tegra_pcie.pll_e);
- clk_put(tegra_pcie.pcie_xclk);
+ if (tegra_pcie.pll_e)
+ clk_put(tegra_pcie.pll_e);
+ if (tegra_pcie.pcie_xclk)
+ clk_put(tegra_pcie.pcie_xclk);
}
static int tegra_pcie_get_resources(void)
{
- struct resource *res_mmio = 0;
int err;
tegra_pcie.power_rails_enabled = 0;
- err = tegra_pcie_enable_regulators();
- if (err) {
- pr_err("PCIE: failed to enable power rails %d\n", err);
- goto err_pwr_on_rail;
- }
- tegra_unpowergate_partition(TEGRA_POWERGATE_PCIE);
+ tegra_pcie.pcie_power_enabled = 0;
err = tegra_pcie_clocks_get();
if (err) {
pr_err("PCIE: failed to get clocks: %d\n", err);
- return err;
+ goto err_clk_get;
}
-
- err = tegra_pcie_power_regate();
+ err = tegra_pcie_power_on();
if (err) {
- pr_err("PCIE: failed to power up: %d\n", err);
+ pr_err("PCIE: Failed to power on: %d\n", err);
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");
- err = -ENOMEM;
- goto err_map_reg;
- }
- res_mmio = &tegra_pcie.res_mmio;
-
- err = request_resource(&iomem_resource, res_mmio);
- if (err) {
- pr_err("PCIE: Failed to request resources: %d\n", err);
- 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) {
- pr_err("PCIE: Failed to map IO\n");
- err = -ENOMEM;
- goto err_map_io;
- }
-
err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
- IRQF_SHARED, "PCIE", &tegra_pcie);
+ IRQF_SHARED, "PCIE", &tegra_pcie);
if (err) {
pr_err("PCIE: Failed to register IRQ: %d\n", err);
- goto err_irq;
+ goto err_pwr_on;
}
set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
-
return 0;
-err_irq:
- iounmap(tegra_pcie_io_base);
-err_map_io:
- release_resource(&tegra_pcie.res_mmio);
-err_req_io:
- iounmap(tegra_pcie.regs);
-err_map_reg:
- tegra_pcie_power_off();
err_pwr_on:
+ tegra_pcie_power_off();
+err_clk_get:
tegra_pcie_clocks_put();
-err_pwr_on_rail:
- tegra_pcie_disable_regulators();
return err;
}
@@ -1205,6 +1233,7 @@ static void tegra_pcie_enable_aspm_l1_support(int index)
static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
{
struct tegra_pcie_port *pp;
+ unsigned int data;
pp = tegra_pcie.port + tegra_pcie.num_ports;
@@ -1219,6 +1248,18 @@ static void tegra_pcie_add_port(int index, u32 offset, u32 reset_reg)
}
tegra_pcie_enable_clock_clamp(index);
tegra_pcie_enable_aspm_l1_support(index);
+
+ /*
+ * Initialize TXBA1 register to fix the unfair arbitration
+ * between downstream reads and completions to upstream reads
+ */
+ data = rp_readl(RP_TXBA1, index);
+ data &= ~(RP_TXBA1_PW_OVER_CM_BURST_MASK);
+ data |= RP_TXBA1_PW_OVER_CM_BURST_INIT_VAL;
+ data &= ~(RP_TXBA1_CM_OVER_PW_BURST_MASK);
+ data |= RP_TXBA1_CM_OVER_PW_BURST_INIT_VAL;
+ rp_writel(data, RP_TXBA1, index);
+
tegra_pcie.num_ports++;
pp->index = index;
memset(pp->res, 0, sizeof(pp->res));
@@ -1254,7 +1295,6 @@ static int tegra_pcie_init(void)
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;
@@ -1294,7 +1334,6 @@ err_irq:
static int tegra_pcie_probe(struct platform_device *pdev)
{
int ret;
- struct pci_dev *dev = NULL;
tegra_pcie.plat_data = pdev->dev.platform_data;
dev_dbg(&pdev->dev, "PCIE.C: %s : _port_status[0] %d\n",
@@ -1305,23 +1344,14 @@ static int tegra_pcie_probe(struct platform_device *pdev)
__func__, tegra_pcie.plat_data->port_status[2]);
ret = tegra_pcie_init();
- /* disable async PM of pci devices to ensure right order */
- /* suspend/resume calls of tegra and bus driver */
- for_each_pci_dev(dev)
- device_disable_async_suspend(&dev->dev);
-
return ret;
}
#ifdef CONFIG_PM
static int tegra_pcie_suspend(struct device *dev)
{
- int ret = 0;
struct pci_dev *pdev = NULL;
- if (!tegra_pcie.num_ports)
- return ret;
-
for_each_pci_dev(pdev) {
pci_remove_bus_device(pdev);
break;
@@ -1329,6 +1359,8 @@ static int tegra_pcie_suspend(struct device *dev)
/* disable read/write registers before powering off */
is_pcie_noirq_op = true;
+ /* reset number of ports since fresh initialization occurs in resume */
+ tegra_pcie.num_ports = 0;
return tegra_pcie_power_off();
}
@@ -1358,24 +1390,31 @@ static int tegra_pcie_resume(struct device *dev)
int port, rp_offset = 0;
int ctrl_offset = AFI_PEX0_CTRL;
- if (!tegra_pcie.num_ports)
- return ret;
+ /* return w/o resume if cardhu dock is not connected */
+ if (gpio_get_value(tegra_pcie.plat_data->gpio))
+ goto exit;
ret = tegra_pcie_power_on();
+ if (ret) {
+ pr_err("PCIE: Failed to power on: %d\n", ret);
+ return ret;
+ }
/* enable read/write registers after powering on */
is_pcie_noirq_op = false;
tegra_pcie_enable_controller();
tegra_pcie_setup_translations();
msi_enable = false;
- /* 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_pcie_add_port(port, rp_offset, ctrl_offset);
}
+ if (!tegra_pcie.num_ports) {
+ tegra_pcie_power_off();
+ goto exit;
+ }
tegra_pcie_hotplug_init();
while ((bus = pci_find_next_bus(bus)) != NULL) {
@@ -1395,8 +1434,8 @@ static int tegra_pcie_resume(struct device *dev)
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
}
-
- return ret;
+exit:
+ return 0;
}
#endif
diff --git a/arch/arm/mach-tegra/pinmux-t3-tables.c b/arch/arm/mach-tegra/pinmux-t3-tables.c
index 09729a4cfbae..988e3bebb43f 100644
--- a/arch/arm/mach-tegra/pinmux-t3-tables.c
+++ b/arch/arm/mach-tegra/pinmux-t3-tables.c
@@ -178,10 +178,10 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
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_PWR2, PC6, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, 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_WR_N, PZ3, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, 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),\
@@ -320,7 +320,7 @@ 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, POPSDMMC4, RSVD, INPUT, 0x32ac),\
+ 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),\
@@ -386,7 +386,7 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
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(SDMMC3_DAT7, PD4, SDMMC3, SPDIF, RSVD, 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),\
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index d1178a820f39..dbd302414c67 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -32,6 +32,7 @@
#include "clock.h"
#include "reset.h"
#include "sleep.h"
+#include "cpu-tegra.h"
bool tegra_all_cpus_booted;
@@ -209,8 +210,16 @@ int boot_secondary(unsigned int cpu, struct task_struct *idle)
/* Early boot, clock infrastructure is not initialized
- CPU mode switch is not allowed */
status = -EINVAL;
- } else
+ } else {
+#ifdef CONFIG_CPU_FREQ
+ /* set cpu rate is within g-mode range before switch */
+ unsigned int speed = max(
+ (unsigned long)tegra_getspeed(0),
+ clk_get_min_rate(cpu_g_clk) / 1000);
+ tegra_update_cpu_speed(speed);
+#endif
status = clk_set_parent(cpu_clk, cpu_g_clk);
+ }
if (status)
goto done;
@@ -287,16 +296,5 @@ void __init platform_smp_prepare_cpus(unsigned int max_cpus)
smp_init_cpus() which also means that it did not initialize the
reset handler. Do it now before the secondary CPUs are started. */
tegra_cpu_reset_handler_init();
-
-#if defined(CONFIG_HAVE_ARM_SCU)
- {
- 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);
- }
-#endif
scu_enable(scu_base);
}
diff --git a/arch/arm/mach-tegra/pm-irq.c b/arch/arm/mach-tegra/pm-irq.c
index 4a3f3c31830c..4e3c06835b2f 100644
--- a/arch/arm/mach-tegra/pm-irq.c
+++ b/arch/arm/mach-tegra/pm-irq.c
@@ -284,10 +284,15 @@ static int tegra_pm_irq_syscore_suspend(void)
wake_enb = 0xffffffff;
}
- /* Clear PMC Wake Status register while going to suspend */
+ /* Clear PMC Wake Status registers while going to suspend */
temp = readl(pmc + PMC_WAKE_STATUS);
if (temp)
pmc_32kwritel(temp, PMC_WAKE_STATUS);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ temp = readl(pmc + PMC_WAKE2_STATUS);
+ if (temp)
+ pmc_32kwritel(temp, PMC_WAKE2_STATUS);
+#endif
write_pmc_wake_level(wake_level);
diff --git a/arch/arm/mach-tegra/pm-t2.c b/arch/arm/mach-tegra/pm-t2.c
index 7ddbb2125595..6b8515ab2e3e 100644
--- a/arch/arm/mach-tegra/pm-t2.c
+++ b/arch/arm/mach-tegra/pm-t2.c
@@ -3,7 +3,7 @@
*
* Tegra 2 LP0 scratch register preservation
*
- * Copyright (c) 2009-2011, 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
@@ -357,6 +357,8 @@ void __init tegra2_lp0_suspend_init(void)
wmb();
}
+#ifdef CONFIG_PM_SLEEP
+
struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev)
{
return NULL;
@@ -374,3 +376,17 @@ void tegra_io_dpd_disable(struct tegra_io_dpd *hnd)
return;
}
EXPORT_SYMBOL(tegra_io_dpd_disable);
+
+#endif
+
+int tegra_io_dpd_init(void)
+{
+ return 0;
+}
+EXPORT_SYMBOL(tegra_io_dpd_init);
+
+void tegra_bl_io_dpd_cleanup()
+{
+}
+EXPORT_SYMBOL(tegra_bl_io_dpd_cleanup);
+
diff --git a/arch/arm/mach-tegra/pm-t3.c b/arch/arm/mach-tegra/pm-t3.c
index a83174224498..939a9b8ad404 100644
--- a/arch/arm/mach-tegra/pm-t3.c
+++ b/arch/arm/mach-tegra/pm-t3.c
@@ -3,7 +3,7 @@
*
* Tegra3 SOC-specific power and cluster management
*
- * 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
@@ -31,6 +31,7 @@
#include <mach/gpio.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
+#include <mach/io_dpd.h>
#include <asm/cpu_pm.h>
#include <asm/hardware/gic.h>
@@ -101,6 +102,12 @@
#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
#define CPU_RESET(cpu) (0x1111ul<<(cpu))
+#define PLLX_FO_G (1<<28)
+#define PLLX_FO_LP (1<<29)
+
+#define CLK_RST_CONTROLLER_PLLX_MISC_0 \
+ (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0xE4)
+
static int cluster_switch_prolog_clock(unsigned int flags)
{
u32 reg;
@@ -188,6 +195,20 @@ static int cluster_switch_prolog_clock(unsigned int flags)
return 0;
}
+static inline void enable_pllx_cluster_port(void)
+{
+ u32 val = readl(CLK_RST_CONTROLLER_PLLX_MISC_0);
+ val &= (is_lp_cluster()?(~PLLX_FO_G):(~PLLX_FO_LP));
+ writel(val, CLK_RST_CONTROLLER_PLLX_MISC_0);
+}
+
+static inline void disable_pllx_cluster_port(void)
+{
+ u32 val = readl(CLK_RST_CONTROLLER_PLLX_MISC_0);
+ val |= (is_lp_cluster()?PLLX_FO_G:PLLX_FO_LP);
+ writel(val, CLK_RST_CONTROLLER_PLLX_MISC_0);
+}
+
void tegra_cluster_switch_prolog(unsigned int flags)
{
unsigned int target_cluster = flags & TEGRA_POWER_CLUSTER_MASK;
@@ -222,6 +243,9 @@ void tegra_cluster_switch_prolog(unsigned int flags)
/* Set up the flow controller to switch CPUs. */
reg |= FLOW_CTRL_CPU_CSR_SWITCH_CLUSTER;
+
+ /* Enable target port of PLL_X */
+ enable_pllx_cluster_port();
}
}
@@ -304,6 +328,9 @@ void tegra_cluster_switch_epilog(unsigned int flags)
cluster_switch_epilog_gic();
}
+ /* Disable unused port of PLL_X */
+ disable_pllx_cluster_port();
+
#if DEBUG_CLUSTER_SWITCH
{
/* FIXME: clock functions below are taking mutex */
@@ -450,16 +477,22 @@ void tegra_lp0_cpu_mode(bool enter)
#define PMC_DPD_SAMPLE 0x20
struct tegra_io_dpd tegra_list_io_dpd[] = {
-/* Empty DPD list - sd dpd entries removed */
+ /* sd dpd bits in dpd2 register */
+ IO_DPD_INFO("sdhci-tegra.0", 1, 1), /* SDMMC1 */
+ IO_DPD_INFO("sdhci-tegra.2", 1, 2), /* SDMMC3 */
+ IO_DPD_INFO("sdhci-tegra.3", 1, 3), /* SDMMC4 */
};
+/* we want to cleanup bootloader io dpd setting in kernel */
+static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+
+#ifdef CONFIG_PM_SLEEP
struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev)
{
int i;
const char *name = dev ? dev_name(dev) : NULL;
if (name) {
- for (i = 0; i < (sizeof(tegra_list_io_dpd) /
- sizeof(struct tegra_io_dpd)); i++) {
+ for (i = 0; i < ARRAY_SIZE(tegra_list_io_dpd); i++) {
if (!(strncmp(tegra_list_io_dpd[i].name, name,
strlen(name)))) {
return &tegra_list_io_dpd[i];
@@ -470,9 +503,7 @@ struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev)
((name) ? name : "NULL"));
return NULL;
}
-EXPORT_SYMBOL(tegra_io_dpd_get);
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
static DEFINE_SPINLOCK(tegra_io_dpd_lock);
void tegra_io_dpd_enable(struct tegra_io_dpd *hnd)
@@ -481,8 +512,10 @@ void tegra_io_dpd_enable(struct tegra_io_dpd *hnd)
unsigned int dpd_status;
unsigned int dpd_enable_lsb;
- if ((!hnd))
+ if ((!hnd)) {
+ pr_warn("SD IO DPD handle NULL in %s\n", __func__);
return;
+ }
spin_lock(&tegra_io_dpd_lock);
dpd_enable_lsb = (hnd->io_dpd_reg_index) ? APBDEV_DPD2_ENABLE_LSB :
APBDEV_DPD_ENABLE_LSB;
@@ -502,7 +535,6 @@ void tegra_io_dpd_enable(struct tegra_io_dpd *hnd)
spin_unlock(&tegra_io_dpd_lock);
return;
}
-EXPORT_SYMBOL(tegra_io_dpd_enable);
void tegra_io_dpd_disable(struct tegra_io_dpd *hnd)
{
@@ -510,8 +542,10 @@ void tegra_io_dpd_disable(struct tegra_io_dpd *hnd)
unsigned int dpd_status;
unsigned int dpd_enable_lsb;
- if ((!hnd))
+ if ((!hnd)) {
+ pr_warn("SD IO DPD handle NULL in %s\n", __func__);
return;
+ }
spin_lock(&tegra_io_dpd_lock);
dpd_enable_lsb = (hnd->io_dpd_reg_index) ? APBDEV_DPD2_ENABLE_LSB :
APBDEV_DPD_ENABLE_LSB;
@@ -526,4 +560,88 @@ void tegra_io_dpd_disable(struct tegra_io_dpd *hnd)
spin_unlock(&tegra_io_dpd_lock);
return;
}
+
+static void tegra_io_dpd_delayed_disable(struct work_struct *work)
+{
+ struct tegra_io_dpd *hnd = container_of(
+ to_delayed_work(work), struct tegra_io_dpd, delay_dpd);
+ tegra_io_dpd_disable(hnd);
+ hnd->need_delay_dpd = 0;
+}
+
+int tegra_io_dpd_init(void)
+{
+ int i;
+ for (i = 0;
+ i < (sizeof(tegra_list_io_dpd) / sizeof(struct tegra_io_dpd));
+ i++) {
+ INIT_DELAYED_WORK(&(tegra_list_io_dpd[i].delay_dpd),
+ tegra_io_dpd_delayed_disable);
+ mutex_init(&(tegra_list_io_dpd[i].delay_lock));
+ tegra_list_io_dpd[i].need_delay_dpd = 0;
+ }
+ return 0;
+}
+
+#else
+
+int tegra_io_dpd_init(void)
+{
+ return 0;
+}
+
+void tegra_io_dpd_enable(struct tegra_io_dpd *hnd)
+{
+}
+
+void tegra_io_dpd_disable(struct tegra_io_dpd *hnd)
+{
+}
+
+struct tegra_io_dpd *tegra_io_dpd_get(struct device *dev)
+{
+ return NULL;
+}
+
+#endif
+
+EXPORT_SYMBOL(tegra_io_dpd_get);
+EXPORT_SYMBOL(tegra_io_dpd_enable);
EXPORT_SYMBOL(tegra_io_dpd_disable);
+EXPORT_SYMBOL(tegra_io_dpd_init);
+
+struct io_dpd_reg_info {
+ u32 req_reg_off;
+ u8 dpd_code_lsb;
+};
+
+static struct io_dpd_reg_info t3_io_dpd_req_regs[] = {
+ {0x1b8, 30},
+ {0x1c0, 5},
+};
+
+/* io dpd off request code */
+#define IO_DPD_CODE_OFF 1
+
+/* cleans io dpd settings from bootloader during kernel init */
+void tegra_bl_io_dpd_cleanup()
+{
+ int i;
+ unsigned int dpd_mask;
+ unsigned int dpd_status;
+
+ pr_info("Clear bootloader IO dpd settings\n");
+ /* clear all dpd requests from bootloader */
+ for (i = 0; i < ARRAY_SIZE(t3_io_dpd_req_regs); i++) {
+ dpd_mask = ((1 << t3_io_dpd_req_regs[i].dpd_code_lsb) - 1);
+ dpd_mask |= (IO_DPD_CODE_OFF <<
+ t3_io_dpd_req_regs[i].dpd_code_lsb);
+ writel(dpd_mask, pmc + t3_io_dpd_req_regs[i].req_reg_off);
+ /* dpd status register is next to req reg in tegra3 */
+ dpd_status = readl(pmc +
+ (t3_io_dpd_req_regs[i].req_reg_off + 4));
+ }
+ return;
+}
+EXPORT_SYMBOL(tegra_bl_io_dpd_cleanup);
+
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 7a08bc1aef24..88dd501689af 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -3,7 +3,7 @@
*
* CPU complex suspend & resume functions for Tegra SoCs
*
- * 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
@@ -178,7 +178,6 @@ struct suspend_context tegra_sctx;
#define MC_SECURITY_SIZE 0x70
#define MC_SECURITY_CFG2 0x7c
-#define AWAKE_CPU_FREQ_MIN 100000
static struct pm_qos_request_list awake_cpu_freq_req;
struct dvfs_rail *tegra_cpu_rail;
@@ -546,17 +545,27 @@ bool tegra_set_cpu_in_lp2(int cpu)
return last_cpu;
}
+bool tegra_is_cpu_in_lp2(int cpu)
+{
+ bool in_lp2;
+
+ spin_lock(&tegra_lp2_lock);
+ in_lp2 = cpumask_test_cpu(cpu, &tegra_in_lp2);
+ spin_unlock(&tegra_lp2_lock);
+ return in_lp2;
+}
+
static void tegra_sleep_core(enum tegra_suspend_mode mode,
unsigned long v2p)
{
#ifdef CONFIG_TRUSTED_FOUNDATIONS
if (mode == TEGRA_SUSPEND_LP0) {
- tegra_generic_smc(0xFFFFFFFC, 0xFFFFFFE3,
- virt_to_phys(tegra_resume));
+ tegra_generic_smc_uncached(0xFFFFFFFC, 0xFFFFFFE3,
+ virt_to_phys(tegra_resume));
} else {
- tegra_generic_smc(0xFFFFFFFC, 0xFFFFFFE6,
- (TEGRA_RESET_HANDLER_BASE +
- tegra_cpu_reset_handler_offset));
+ tegra_generic_smc_uncached(0xFFFFFFFC, 0xFFFFFFE6,
+ (TEGRA_RESET_HANDLER_BASE +
+ tegra_cpu_reset_handler_offset));
}
#endif
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
@@ -569,9 +578,19 @@ static void tegra_sleep_core(enum tegra_suspend_mode mode,
static inline void tegra_sleep_cpu(unsigned long v2p)
{
#ifdef CONFIG_TRUSTED_FOUNDATIONS
- tegra_generic_smc(0xFFFFFFFC, 0xFFFFFFE4,
- (TEGRA_RESET_HANDLER_BASE +
- tegra_cpu_reset_handler_offset));
+ if (tegra_is_cpu_in_lp2(0)) {
+ struct thread_info *thread;
+
+ /* flush thread state (sleep SMC will also disable L2) */
+ thread = current_thread_info();
+ BUG_ON(!thread);
+
+ __cpuc_flush_dcache_area(thread, THREAD_SIZE);
+ outer_flush_range(__pa(thread), __pa(thread) + THREAD_SIZE);
+ }
+ tegra_generic_smc_uncached(0xFFFFFFFC, 0xFFFFFFE4,
+ (TEGRA_RESET_HANDLER_BASE +
+ tegra_cpu_reset_handler_offset));
#endif
tegra_sleep_cpu_save(v2p);
}
@@ -1085,13 +1104,17 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
u32 reg;
u32 mode;
+ if (plat->cpu_wake_freq == 0)
+ plat->cpu_wake_freq = CPU_WAKE_FREQ_HIGH;
+
tegra_cpu_rail = tegra_dvfs_get_rail_by_name("vdd_cpu");
tegra_core_rail = tegra_dvfs_get_rail_by_name("vdd_core");
pm_qos_add_request(&awake_cpu_freq_req, PM_QOS_CPU_FREQ_MIN,
- AWAKE_CPU_FREQ_MIN);
+ plat->cpu_wake_freq);
tegra_pclk = clk_get_sys(NULL, "pclk");
BUG_ON(IS_ERR(tegra_pclk));
+
pdata = plat;
(void)reg;
(void)mode;
@@ -1176,6 +1199,21 @@ out:
plat->suspend_mode = TEGRA_SUSPEND_LP2;
}
+#ifdef CONFIG_TEGRA_LP1_950
+ if (pdata->lp1_lowvolt_support) {
+ u32 lp1_core_lowvolt, lp1_core_highvolt;
+ memcpy(tegra_lp1_register_pmuslave_addr(), &pdata->pmuslave_addr, 4);
+ memcpy(tegra_lp1_register_i2c_base_addr(), &pdata->i2c_base_addr, 4);
+
+ lp1_core_lowvolt = 0;
+ lp1_core_lowvolt = (pdata->lp1_core_volt_low << 8) | pdata->core_reg_addr;
+ memcpy(tegra_lp1_register_core_lowvolt(), &lp1_core_lowvolt, 4);
+
+ lp1_core_highvolt = 0;
+ lp1_core_highvolt = (pdata->lp1_core_volt_high << 8) | pdata->core_reg_addr;
+ memcpy(tegra_lp1_register_core_highvolt(), &lp1_core_highvolt, 4);
+ }
+#endif
/* !!!FIXME!!! THIS IS TEGRA2 ONLY */
/* Initialize scratch registers used for CPU LP2 synchronization */
writel(0, pmc + PMC_SCRATCH37);
@@ -1231,6 +1269,10 @@ out:
iram_cpu_lp2_mask = tegra_cpu_lp2_mask;
iram_cpu_lp1_mask = tegra_cpu_lp1_mask;
+
+ /* clear io dpd settings before kernel */
+ tegra_bl_io_dpd_cleanup();
+
fail:
#endif
if (plat->suspend_mode == TEGRA_SUSPEND_NONE)
@@ -1344,7 +1386,7 @@ static void pm_late_resume(struct early_suspend *h)
{
if (clk_wake)
clk_enable(clk_wake);
- pm_qos_update_request(&awake_cpu_freq_req, (s32)AWAKE_CPU_FREQ_MIN);
+ pm_qos_update_request(&awake_cpu_freq_req, (s32)pdata->cpu_wake_freq);
}
static struct early_suspend pm_early_suspender = {
diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h
index 421b21ac9342..401c0aaf061f 100644
--- a/arch/arm/mach-tegra/pm.h
+++ b/arch/arm/mach-tegra/pm.h
@@ -2,7 +2,7 @@
* arch/arm/mach-tegra/include/mach/pm.h
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved.
*
* Author:
* Colin Cross <ccross@google.com>
@@ -33,6 +33,16 @@
#define PMC_SCRATCH1 0x54
#define PMC_SCRATCH4 0x60
+/* The following two constants are for setting the CPU freq
+ * floor when display is on. 204000Khz is for tablet and
+ * 102000KHz is for phones. The reason for different values
+ * for tablet and phone is due to phones usually have smart
+ * displays that requires less CPU activity for refreshing
+ * the screen
+ */
+
+#define CPU_WAKE_FREQ_HIGH 204000
+#define CPU_WAKE_FREQ_LOW 102000
enum tegra_suspend_mode {
TEGRA_SUSPEND_NONE = 0,
TEGRA_SUSPEND_LP2, /* CPU voltage off */
@@ -65,20 +75,26 @@ struct tegra_suspend_platform_data {
/* lp_state = 0 for LP0 state, 1 for LP1 state, 2 for LP2 state */
void (*board_resume)(int lp_state, enum resume_stage stg);
unsigned int cpu_resume_boost; /* CPU frequency resume boost in kHz */
+#ifdef CONFIG_TEGRA_LP1_950
+ bool lp1_lowvolt_support;
+ unsigned int i2c_base_addr;
+ unsigned int pmuslave_addr;
+ unsigned int core_reg_addr;
+ unsigned int lp1_core_volt_low;
+ unsigned int lp1_core_volt_high;
+#endif
+ int cpu_wake_freq;
};
-/* Tegra io dpd entry - for each supported driver */
-struct tegra_io_dpd {
- const char *name; /* driver name */
- u8 io_dpd_reg_index; /* io dpd register index */
- u8 io_dpd_bit; /* bit position for driver in dpd register */
-};
+/* clears io dpd settings before kernel code */
+void tegra_bl_io_dpd_cleanup(void);
unsigned long tegra_cpu_power_good_time(void);
unsigned long tegra_cpu_power_off_time(void);
unsigned long tegra_cpu_lp2_min_residency(void);
void tegra_clear_cpu_in_lp2(int cpu);
bool tegra_set_cpu_in_lp2(int cpu);
+bool tegra_is_cpu_in_lp2(int cpu);
int tegra_suspend_dram(enum tegra_suspend_mode mode, unsigned int flags);
@@ -226,6 +242,8 @@ extern bool tegra_all_cpus_booted __read_mostly;
#ifdef CONFIG_TRUSTED_FOUNDATIONS
void tegra_generic_smc(u32 type, u32 subtype, u32 arg);
+void tegra_generic_smc_local(u32 type, u32 subtype, u32 arg);
+void tegra_generic_smc_uncached(u32 type, u32 subtype, u32 arg);
#endif
/* The debug channel uart base physical address */
diff --git a/arch/arm/mach-tegra/pwm.c b/arch/arm/mach-tegra/pwm.c
index a268c391cb27..d5533c7d3c05 100644
--- a/arch/arm/mach-tegra/pwm.c
+++ b/arch/arm/mach-tegra/pwm.c
@@ -87,9 +87,10 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
if (rate >> PWM_SCALE_WIDTH)
return -EINVAL;
- /* Due to the PWM divider is zero-based, we need to minus 1 to get desired frequency*/
- if (rate>0)
- rate--;
+ /* Due to the PWM divider is zero-based, we need to minus 1 to get
+ *desired frequency*/
+ if (rate > 0)
+ rate--;
val |= (rate << PWM_SCALE_SHIFT);
@@ -182,19 +183,16 @@ static int tegra_pwm_probe(struct platform_device *pdev)
{
struct pwm_device *pwm;
struct resource *r;
- int ret;
- pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
+ pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
if (!pwm) {
dev_err(&pdev->dev, "failed to allocate memory\n");
return -ENOMEM;
}
- pwm->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(pwm->clk)) {
- ret = PTR_ERR(pwm->clk);
- goto err_free;
- }
+ pwm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm->clk))
+ return PTR_ERR(pwm->clk);
pwm->clk_enb = 0;
pwm->in_use = 0;
@@ -204,22 +202,13 @@ static int tegra_pwm_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) {
dev_err(&pdev->dev, "no memory resources defined\n");
- ret = -ENODEV;
- goto err_put_clk;
- }
-
- r = request_mem_region(r->start, resource_size(r), pdev->name);
- if (!r) {
- dev_err(&pdev->dev, "failed to request memory\n");
- ret = -EBUSY;
- goto err_put_clk;
+ return -ENODEV;
}
- pwm->mmio_base = ioremap(r->start, resource_size(r));
+ pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
if (!pwm->mmio_base) {
- dev_err(&pdev->dev, "failed to ioremap() region\n");
- ret = -ENODEV;
- goto err_free_mem;
+ dev_err(&pdev->dev, "failed to request/ioremap memory\n");
+ return -EADDRNOTAVAIL;
}
platform_set_drvdata(pdev, pwm);
@@ -230,13 +219,7 @@ static int tegra_pwm_probe(struct platform_device *pdev)
return 0;
-err_free_mem:
- release_mem_region(r->start, resource_size(r));
-err_put_clk:
- clk_put(pwm->clk);
-err_free:
- kfree(pwm);
- return ret;
+
}
static int __devexit tegra_pwm_remove(struct platform_device *pdev)
@@ -259,16 +242,9 @@ static int __devexit tegra_pwm_remove(struct platform_device *pdev)
mutex_unlock(&pwm_lock);
rc = pwm_writel(pwm, 0);
-
- iounmap(pwm->mmio_base);
- release_mem_region(r->start, resource_size(r));
-
if (pwm->clk_enb)
clk_disable(pwm->clk);
- clk_put(pwm->clk);
-
- kfree(pwm);
return rc;
}
diff --git a/arch/arm/mach-tegra/sleep-t3.S b/arch/arm/mach-tegra/sleep-t3.S
index 23e96c605b96..4ee73d581a08 100644
--- a/arch/arm/mach-tegra/sleep-t3.S
+++ b/arch/arm/mach-tegra/sleep-t3.S
@@ -95,6 +95,16 @@
#define PMC_PLLM_WB0_OVERRIDE 0x1dc
#define CLK_RESET_CLK_SOURCE_MSELECT 0x3b4
+#define CLK_RESET_CLK_ENB_H_SET 0x328
+#define CLK_RESET_CLK_ENB_H_CLR 0x32c
+#define CLK_RESET_CLK_RST_DEV_H_SET 0x308
+#define CLK_RESET_CLK_RST_DEV_H_CLR 0x30c
+
+#define I2C_CNFG 0x0
+#define I2C_ADDR0 0x4
+#define I2C_DATA1 0xc
+#define I2C_DATA2 0x10
+#define I2C_STATUS 0x1c
#define MSELECT_CLKM (0x3 << 30)
@@ -348,6 +358,66 @@ ENTRY(tegra3_lp1_reset)
mov32 r4, ((1<<28) | (8)) @ burst policy is PLLX
str r4, [r0, #CLK_RESET_CCLK_BURST]
+#ifdef CONFIG_TEGRA_LP1_950
+lp1_voltset:
+ /* Restore the Core voltage to high on LP1 resume */
+ /* Reset(Enable/Disable) the DVC-I2C Controller*/
+ mov r1, #(1 << 15)
+ str r1, [r0, #CLK_RESET_CLK_RST_DEV_H_SET]
+
+ /* Wait for 2us */
+ mov32 r7, TEGRA_TMRUS_BASE
+ wait_for_us r1, r7, r9
+ add r1, r1, #2
+ wait_until r1, r7, r9
+
+ mov r1, #(1 << 15)
+ str r1, [r0, #CLK_RESET_CLK_RST_DEV_H_CLR]
+
+ /* Enable the DVC-I2C Controller */
+ mov r1, #(1 << 15)
+ str r1, [r0, #CLK_RESET_CLK_ENB_H_SET]
+
+
+ /* Same I2C transaction protocol as suspend */
+ ldr r1, lp1_register_pmuslave_addr
+ cmp r1, #0
+ beq lp1_voltskip_resume
+
+ ldr r4, lp1_register_i2c_base_addr
+ str r1, [r4, #I2C_ADDR0]
+
+ mov32 r1, 0x2
+ str r1, [r4, #I2C_CNFG]
+
+ ldr r1, lp1_register_core_highvolt
+ str r1, [r4, #I2C_DATA1]
+
+ mov32 r1, 0
+ str r1, [r4, #I2C_DATA2]
+
+ mov32 r1, 0xA02
+ str r1, [r4, #I2C_CNFG]
+
+ wait_for_us r1, r7, r9
+ mov32 r3, 0x7D0 /* Wait for 2ms and try transaction again */
+ add r0, r1, r3
+loop_i2c_status_resume:
+ add r1, r1, #0xFA /* Check status every 250us */
+ wait_until r1, r7, r9
+ cmp r0, r1
+ beq lp1_voltset
+
+ ldr r3, [r4, #I2C_STATUS]
+ cmp r3, #0
+ bne loop_i2c_status_resume
+
+lp1_voltskip_resume:
+ /* Disable the DVC-I2C Controller */
+ mov r0, #(1 << 15)
+ str r0, [r5, #CLK_RESET_CLK_ENB_H_CLR]
+#endif
+
#if defined (CONFIG_CACHE_L2X0)
/* power up L2 */
ldr r0, [r2, #PMC_PWRGATE_STATUS]
@@ -492,6 +562,21 @@ tegra3_sdram_pad_address:
tegra3_sdram_pad_size:
.word tegra3_sdram_pad_address - tegra3_sdram_pad_save
+#ifdef CONFIG_TEGRA_LP1_950
+ .globl lp1_register_pmuslave_addr
+ .globl lp1_register_i2c_base_addr
+ .globl lp1_register_core_lowvolt
+ .globl lp1_register_core_highvolt
+lp1_register_pmuslave_addr:
+ .word 0
+lp1_register_i2c_base_addr:
+ .word 0
+lp1_register_core_lowvolt:
+ .word 0
+lp1_register_core_highvolt:
+ .word 0
+#endif
+
/*
* tegra3_tear_down_core
*
@@ -526,9 +611,72 @@ tegra3_cpu_clk32k:
str r0, [r4, #PMC_PLLM_WB0_OVERRIDE]
mov pc, lr
+lp1_clocks_prepare:
+ /* Prepare to set the Core to the lowest voltage if supported.
+ * Start by setting the I2C clocks to make the I2C transfer */
+#ifdef CONFIG_TEGRA_LP1_950
+ /* Set up the PWR I2C GPIOs with the right masks*/
+
+ /* Reset(Set/Clr) the DVC-I2C Controller*/
+ mov r0, #(1 << 15)
+ str r0, [r5, #CLK_RESET_CLK_RST_DEV_H_SET]
+
+ /* Wait for 2us */
+ wait_for_us r1, r7, r9
+ mov32 r0, 0x7D0
+ add r1, r1, r0
+ wait_until r1, r7, r9
+
+ mov r0, #(1 << 15)
+ str r0, [r5, #CLK_RESET_CLK_RST_DEV_H_CLR]
+
+ /* Enable the DVC-I2C Controller */
+ mov r0, #(1 << 15)
+ str r0, [r5, #CLK_RESET_CLK_ENB_H_SET]
+
+ /* I2C transfer protocol:
+ * 4 packets: Slaveaddr + WriteConfigure + Data1 + Data2 */
+ ldr r0, lp1_register_pmuslave_addr
+ cmp r0, #0
+ beq lp1_volt_skip
+ ldr r1, lp1_register_i2c_base_addr
+ str r0, [r1, #I2C_ADDR0]
+
+ mov32 r0, 0x2
+ str r0, [r1, #I2C_CNFG]
+
+ ldr r0, lp1_register_core_lowvolt
+ str r0, [r1, #I2C_DATA1]
+
+ mov32 r0, 0
+ str r0, [r1, #I2C_DATA2]
+
+ /* Send I2C transaction */
+ mov32 r0, 0xA02
+ str r0, [r1, #I2C_CNFG]
+
+ /* Check the transaction status before proceeding */
+ wait_for_us r2, r7, r9
+ mov32 r3, 0x7D0 /* Wait for 2ms for I2C transaction */
+ add r3, r2, r3
+loop_i2c_status_suspend:
+ add r2, r2, #0xFA /* Check status every 250us */
+ cmp r3, r2
+ beq lp1_volt_skip /* Waited for 2ms, I2C transaction didn't take place */
+ wait_until r2, r7, r9
+
+ ldr r0, [r1, #I2C_STATUS]
+ cmp r0, #0
+ bne loop_i2c_status_suspend
+lp1_volt_skip:
+
+ /* Disable the DVC-I2C Controller */
+ mov r0, #(1 << 15)
+ str r0, [r5, #CLK_RESET_CLK_ENB_H_CLR]
+
+#endif
/* start by jumping to clkm to safely disable PLLs, then jump
* to clks */
-lp1_clocks_prepare:
mov r0, #(1 << 28)
str r0, [r5, #CLK_RESET_SCLK_BURST]
str r0, [r5, #CLK_RESET_CCLK_BURST]
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
index 973c8677bafe..e86795c5c46a 100644
--- a/arch/arm/mach-tegra/sleep.S
+++ b/arch/arm/mach-tegra/sleep.S
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/sleep.S
*
- * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
* Copyright (c) 2011, Google, Inc.
*
* Author: Colin Cross <ccross@android.com>
@@ -440,28 +440,83 @@ ENDPROC(tegra_cpu_pllp)
#endif
#ifdef CONFIG_TRUSTED_FOUNDATIONS
+
/*
- * tegra_generic_smc
+ * Confirm we're issuing this SMC from CPU0 (only one
+ * currently supported) and issue the instruction.
*
* r0 = smc type
* r1 = smc subtype
* r2 = argument passed to smc
- *
- * issues SMC (secure monitor call) instruction with
- * the specified parameters.
*/
-ENTRY(tegra_generic_smc)
- adr r3, __tegra_smc_stack
- stmia r3, {r4-r12, lr}
+.macro smc_issue_smc tmp
+ cpu_id \tmp
+ cmp \tmp, #0
+ bne .
mov r3, #0
mov r4, #0
dsb
smc #0
- adr r3, __tegra_smc_stack
- ldmia r3, {r4-r12, pc}
+.endm
+
+/*
+ * Issue SMC with ctx kept on an uncached stack
+ */
+ENTRY(tegra_generic_smc_uncached)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_CACHE_L2X0)
+ mov32 r3, tegra_cpu_context @ borrow CPU0's non-cached
+ ldr r3, [r3] @ context grows up
+ stmia r3, {r4-r12, sp, lr}
+
+ smc_issue_smc r5
+
+ mov32 r3, tegra_cpu_context @ borrow CPU0's non-cached
+ ldr r3, [r3] @ context grows up
+ ldmia r3, {r4-r12, sp, pc}
+#else
+ mov pc, lr
+#endif
+ENDPROC(tegra_generic_smc_uncached)
+
+/*
+ * Issue SMC with ctx kept on a cacheable stack
+ * (args in R0, R1, R2 and R3 holds save/restore ptr)
+ */
+ENTRY(tegra_generic_smc_cached)
+ stmia r3, {r4-r12, sp, lr}
+ adr r4, __tegra_smc_current_ctx @ save current ptr
+ str r3, [r4]
+
+ smc_issue_smc r5
+
+ adr r4, __tegra_smc_current_ctx @ restore from saved ptr
+ ldr r3, [r4]
+ ldmia r3, {r4-r12, sp, pc}
+ENDPROC(tegra_generic_smc_cached)
+ .type __tegra_smc_current_ctx, %object
+__tegra_smc_current_ctx:
+ .long 0
+ .size __tegra_smc_current_ctx, . - __tegra_smc_current_ctx
+
+#define TEGRA_SMC_SAVED_WORDS 11
+
+/* SMC issued using the current cacheable SP stack */
+ENTRY(tegra_generic_smc)
+ mov r3, sp @ use current stack
+ sub r3, #(TEGRA_SMC_SAVED_WORDS << 2) @ context grows up
+ b tegra_generic_smc_cached
ENDPROC(tegra_generic_smc)
- .type __tegra_smc_stack, %object
+
+/* SMC issued using a local cacheable stack */
+ENTRY(tegra_generic_smc_local)
+ adr r3, __tegra_smc_stack @ use local stack
+ b tegra_generic_smc_cached
+ENDPROC(tegra_generic_smc_local)
+ .align L1_CACHE_SHIFT
+ .type __tegra_smc_stack, %object
__tegra_smc_stack:
- .long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ .rept TEGRA_SMC_SAVED_WORDS
+ .long 0
+ .endr
.size __tegra_smc_stack, . - __tegra_smc_stack
#endif
diff --git a/arch/arm/mach-tegra/sleep.h b/arch/arm/mach-tegra/sleep.h
index c57399985ecd..48b2bb8cfdb2 100644
--- a/arch/arm/mach-tegra/sleep.h
+++ b/arch/arm/mach-tegra/sleep.h
@@ -223,6 +223,10 @@ void tegra2_sleep_wfi(unsigned long v2p);
#else
extern unsigned int tegra3_iram_start;
extern unsigned int tegra3_iram_end;
+extern unsigned int lp1_register_pmuslave_addr;
+extern unsigned int lp1_register_i2c_base_addr;
+extern unsigned int lp1_register_core_lowvolt;
+extern unsigned int lp1_register_core_highvolt;
void tegra3_sleep_core(unsigned long v2p);
void tegra3_sleep_cpu_secondary(unsigned long v2p);
void tegra3_hotplug_shutdown(void);
@@ -245,5 +249,41 @@ static inline void *tegra_iram_end(void)
return &tegra3_iram_end;
#endif
}
+
+static inline void *tegra_lp1_register_pmuslave_addr(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_pmuslave_addr;
+#endif
+}
+
+static inline void *tegra_lp1_register_i2c_base_addr(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_i2c_base_addr;
+#endif
+}
+
+static inline void *tegra_lp1_register_core_lowvolt(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_core_lowvolt;
+#endif
+}
+
+static inline void *tegra_lp1_register_core_highvolt(void)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ return NULL;
+#else
+ return &lp1_register_core_highvolt;
+#endif
+}
#endif
#endif
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 65434963d7d7..58d2dcddbfaa 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -2462,14 +2462,14 @@ struct clk tegra_list_periph_clks[] = {
PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("nor", "tegra-nor", NULL, 42, 0x1d0, 0x31E, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 0x31E, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
- PERIPH_CLK("i2c1", "tegra-i2c.0", "i2c-div", 12, 0x124, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c2", "tegra-i2c.1", "i2c-div", 54, 0x198, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c3", "tegra-i2c.2", "i2c-div", 67, 0x1b8, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("dvc", "tegra-i2c.3", "i2c-div", 47, 0x128, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c1-fast", "tegra-i2c.0", "i2c-fast", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("i2c2-fast", "tegra-i2c.1", "i2c-fast", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("i2c3-fast", "tegra-i2c.2", "i2c-fast", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("dvc-fast", "tegra-i2c.3", "i2c-fast", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c1", "tegra-i2c.0", "div-clk", 12, 0x124, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c2", "tegra-i2c.1", "div-clk", 54, 0x198, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c3", "tegra-i2c.2", "div-clk", 67, 0x1b8, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("dvc", "tegra-i2c.3", "div-clk", 47, 0x128, 0x31E, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c1-fast", "tegra-i2c.0", "fast-clk", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c2-fast", "tegra-i2c.1", "fast-clk", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c3-fast", "tegra-i2c.2", "fast-clk", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("dvc-fast", "tegra-i2c.3", "fast-clk", 0, 0, 0x31E, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 0x31E, 600000000, mux_pllp_pllc_pllm_clkm, MUX | PERIPH_ON_APB),
PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 0x31E, 600000000, mux_pllp_pllc_pllm_clkm, MUX | PERIPH_ON_APB),
PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 0x31E, 600000000, mux_pllp_pllc_pllm_clkm, MUX | PERIPH_ON_APB),
diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c
index 6e0801625614..121a84b2bcb0 100644
--- a/arch/arm/mach-tegra/tegra2_usb_phy.c
+++ b/arch/arm/mach-tegra/tegra2_usb_phy.c
@@ -47,11 +47,13 @@
#define USB_USBSTS_SRI (1 << 7)
#define USB_USBSTS_HCH (1 << 12)
+#define USB_USBINTR 0x148
+
#define USB_ASYNCLISTADDR 0x158
#define USB_TXFILLTUNING 0x164
#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
-#define USB_FIFO_TXFILL_MASK 0x1f0000
+#define USB_FIFO_TXFILL_MASK 0x3f0000
#define ULPI_VIEWPORT 0x170
#define ULPI_WAKEUP (1 << 31)
@@ -69,6 +71,7 @@
#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)
@@ -277,6 +280,11 @@
#define DBG(stuff...) do {} while (0)
#endif
+/* define HSIC phy params */
+#define HSIC_SYNC_START_DELAY 9
+#define HSIC_IDLE_WAIT_DELAY 17
+#define HSIC_ELASTIC_UNDERRUN_LIMIT 16
+#define HSIC_ELASTIC_OVERRUN_LIMIT 16
static DEFINE_SPINLOCK(utmip_pad_lock);
static int utmip_pad_count;
@@ -605,13 +613,21 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy)
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);
+ if (val & USB_PORTSC_CCS)
+ val &= ~USB_PORTSC_WKCN;
+ else
+ val &= ~USB_PORTSC_WKDS;
+ val &= ~USB_PORTSC_RWC_BITS;
writel(val , (base + USB_PORTSC));
+
+ } else if (!phy->phy_clk_on) {
+ return IRQ_NONE;
}
} else if (!phy->phy_clk_on) {
return IRQ_NONE;
@@ -702,21 +718,27 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
enable_hotplug = (val & USB_ID_STATUS) ? false : true;
}
if (enable_hotplug) {
+ /* Enable wakeup event of device plug-in/plug-out */
val = readl(base + USB_PORTSC);
- val |= USB_PORTSC_WKCN;
+ if (val & USB_PORTSC_CCS)
+ val |= USB_PORTSC_WKDS;
+ else
+ 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*/
+ /* 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);
}
}
+ /* Disable PHY clock */
if (phy->inst == 2) {
val = readl(base + USB_PORTSC);
val |= USB_PORTSC_PHCD;
@@ -932,7 +954,8 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy)
if (usb_phy_reg_status_wait(base + USB_USBCMD,
USB_USBCMD_RESET, 0, 2500) < 0) {
- pr_err("%s: timeout waiting for reset\n", __func__);
+ pr_err("%s: timeout waiting for reset\n",
+ __func__);
}
val = readl(base + USB_USBMODE_REG_OFFSET);
@@ -949,7 +972,8 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy)
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__);
+ pr_err("%s: timeout waiting for run bit\n",
+ __func__);
}
/* Enable Port Power */
@@ -959,7 +983,8 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy)
udelay(10);
DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
- readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ readl(base + USB_USBSTS),
+ readl(base + USB_PORTSC));
}
} else {
/* Restoring the pad powers */
@@ -1051,7 +1076,6 @@ 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) {
@@ -1077,13 +1101,13 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
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);
+ val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_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);
+ val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY);
writel(val, base + UHSIC_HSRX_CFG1);
val = readl(base + UHSIC_MISC_CFG0);
@@ -1354,7 +1378,7 @@ static int ulpi_link_phy_open(struct tegra_usb_phy *phy)
phy->ulpi_vp = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
phy->ulpi_vp->io_priv = phy->regs + ULPI_VIEWPORT;
-
+ phy->linkphy_init = true;
return err;
}
@@ -1450,49 +1474,74 @@ static int ulpi_link_phy_power_on(struct tegra_usb_phy *phy)
}
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);
+ /* Case for lp0 */
+ if (!(val & UHSIC_RESET)) {
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
- val = readl(base + USB_SUSP_CTRL);
- val |= ULPI_PHY_ENABLE;
- writel(val, base + USB_SUSP_CTRL);
+ val = 0;
+ writel(val, base + ULPI_TIMING_CTRL_1);
- val = readl(base + USB_SUSP_CTRL);
- val |= USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
+ ulpi_set_trimmer(phy);
- 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__);
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_NORMAL);
+ tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_NORMAL);
+#endif
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
- 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__);
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500) < 0)
+ pr_err("%s: timeout waiting for phy" \
+ "to stabilize\n", __func__);
- val = readl(base + USB_SUSP_CTRL);
- val &= ~USB_SUSP_CLR;
- writel(val, base + USB_SUSP_CTRL);
+ 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);
+ }
+ } else {
+ /* Case for auto resume*/
+ 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);
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500) < 0)
+ pr_err("%s: timeout waiting for phy" \
+ "to stabilize\n", __func__);
- ulpi_set_trimmer(phy);
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_CLKEN, USB_CLKEN, 2500) < 0)
+ pr_err("%s: timeout waiting for AHB clock\n", __func__);
- /* 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;
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
}
+ if (phy->linkphy_init) {
+ /* To be done only incase of coldboot*/
+ /* 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;
+ ret = otg_io_write(phy->ulpi_vp, 0x80, 0x0B);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+ phy->linkphy_init = false;
}
val = readl(base + USB_PORTSC);
@@ -1510,6 +1559,7 @@ 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_CDEV2, tristate);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate);
@@ -1535,6 +1585,7 @@ static void ulpi_link_phy_restore_end(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);
@@ -1543,6 +1594,13 @@ static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy)
writel(val, base + ULPI_TIMING_CTRL_0);
ulpi_link_phy_set_tristate(false);
+
+ udelay(10);
+ ret = otg_io_write(phy->ulpi_vp, 0x55, 0x04);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return;
+ }
}
static int ulpi_link_phy_resume(struct tegra_usb_phy *phy)
@@ -1562,7 +1620,70 @@ static int ulpi_link_phy_resume(struct tegra_usb_phy *phy)
return status;
}
-static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable)
+static int ulpi_link_phy_pre_resume(struct tegra_usb_phy *phy,
+ bool remote_wakeup)
+{
+ int status = 0;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_RESUME) {
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+
+ /* detect remote wakeup */
+ msleep(20);
+
+ val = readl(base + USB_PORTSC);
+
+ /* Poll until the controller clears RESUME and SUSPEND */
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PORTSC_RESUME, 0, 2500))
+ pr_err("%s: timeout waiting for RESUME\n", __func__);
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PORTSC_SUSP, 0, 2500))
+ pr_err("%s: timeout waiting for SUSPEND\n", __func__);
+
+ /* Since we skip remote wakeup event,
+ put controller in suspend again and
+ resume port later */
+ val = readl(base + USB_PORTSC);
+ val |= USB_PORTSC_SUSP;
+ writel(val, base + USB_PORTSC);
+ mdelay(4);
+ /* Wait until port suspend completes */
+ if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL,
+ USB_PORTSC_SUSP, USB_PORTSC_SUSP, 2500))
+ pr_err("%s: timeout waiting for" \
+ "PORT_SUSPEND\n", __func__);
+
+ /* 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__);
+ }
+ usb_phy_wait_for_sof(phy);
+
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ }
+ return status;
+}
+
+
+static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy,
+ bool enable)
{
unsigned long val;
void __iomem *base = phy->regs;
@@ -1795,7 +1916,8 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
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_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST)
+ ? 3 : 1);
val |= ULPIS2S_PLLU_MASTER_BLASTER60;
writel(val, base + ULPIS2S_CTRL);
@@ -1906,6 +2028,7 @@ static struct tegra_usb_phy_ops ulpi_link_phy_ops = {
.power_on = ulpi_link_phy_power_on,
.power_off = ulpi_link_phy_power_off,
.resume = ulpi_link_phy_resume,
+ .pre_resume = ulpi_link_phy_pre_resume,
};
static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index eba959c9e2d3..468f50dee329 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -319,6 +319,7 @@ static int tegra3_emc_relock_set_rate(struct clk *emc, unsigned long old_rate,
static unsigned long cpu_stay_on_backup_max;
static struct clk *emc_bridge;
+static struct clk *cpu_mode_sclk;
static bool detach_shared_bus;
module_param(detach_shared_bus, bool, 0644);
@@ -1053,6 +1054,8 @@ static int tegra3_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
flags |= (p->u.cpu.mode == MODE_LP) ? TEGRA_POWER_CLUSTER_LP :
TEGRA_POWER_CLUSTER_G;
+ clk_enable(cpu_mode_sclk); /* set SCLK floor for cluster switch */
+
/* Since in both LP and G mode CPU main and backup sources are the
same, set rate on the new parent just synchronizes super-clock
muxes before mode switch with no PLL re-locking */
@@ -1060,6 +1063,7 @@ static int tegra3_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
if (ret) {
pr_err("%s: Failed to set rate %lu for %s\n",
__func__, rate, p->name);
+ clk_disable(cpu_mode_sclk);
return ret;
}
@@ -1075,6 +1079,7 @@ static int tegra3_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
clk_disable(p);
pr_err("%s: Failed to switch %s mode to %s\n",
__func__, c->name, p->name);
+ clk_disable(cpu_mode_sclk);
return ret;
}
@@ -1083,6 +1088,7 @@ static int tegra3_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
clk_disable(c->parent);
clk_reparent(c, p);
+ clk_disable(cpu_mode_sclk);
return 0;
}
@@ -1398,11 +1404,11 @@ static int tegra3_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg, u32 lock_bi
#if USE_PLL_LOCK_BITS
int i;
for (i = 0; i < c->u.pll.lock_delay; i++) {
+ udelay(2); /* timeout = 2 * lock time */
if (clk_readl(lock_reg) & lock_bit) {
udelay(PLL_POST_LOCK_DELAY);
return 0;
}
- udelay(2); /* timeout = 2 * lock time */
}
pr_err("Timed out waiting for lock bit on pll %s", c->name);
return -1;
@@ -1559,6 +1565,7 @@ static int tegra3_pll_clk_enable(struct clk *c)
val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+ pmc_readl(PMC_PLLP_WB0_OVERRIDE);
}
tegra3_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK);
@@ -3076,6 +3083,7 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
unsigned long rate = bus->min_rate;
unsigned long bw = 0;
unsigned long ceiling = bus->max_rate;
+ u8 emc_bw_efficiency = tegra_emc_bw_efficiency_boost;
if (detach_shared_bus)
return 0;
@@ -3089,6 +3097,9 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
*/
if (c->u.shared_bus_user.enabled ||
(c->u.shared_bus_user.mode == SHARED_CEILING)) {
+ if (!strcmp(c->name, "3d.emc"))
+ emc_bw_efficiency = tegra_emc_bw_efficiency;
+
switch (c->u.shared_bus_user.mode) {
case SHARED_BW:
if (bw < bus->max_rate)
@@ -3108,8 +3119,8 @@ 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 = emc_bw_efficiency ?
+ (bw / emc_bw_efficiency) : bus->max_rate;
bw = (bw < bus->max_rate / 100) ?
(bw * 100) : bus->max_rate;
}
@@ -4224,18 +4235,21 @@ static struct clk tegra_clk_emc_bridge = {
.parent = &tegra_clk_emc,
};
+static RAW_NOTIFIER_HEAD(cbus_rate_change_nh);
+
static struct clk tegra_clk_cbus = {
.name = "cbus",
.parent = &tegra_pll_c,
.ops = &tegra_clk_cbus_ops,
.max_rate = 700000000,
.mul = 1,
- .div = 2,
+ .div = CONFIG_TEGRA_CBUS_CLOCK_DIVIDER,
.flags = PERIPH_ON_CBUS,
.shared_bus_backup = {
.input = &tegra_pll_p,
.value = 2,
- }
+ },
+ .rate_change_nh = &cbus_rate_change_nh,
};
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
@@ -4293,7 +4307,7 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("fuse_burn", "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("apbif", "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
@@ -4306,9 +4320,9 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("spdif_in", "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 408000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("d_audio", "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("dam0", "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("dam1", "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("dam2", "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("dam0", "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("dam1", "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("dam2", "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("hda", "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("hda2codec_2x", "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("hda2hdmi", "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, PERIPH_ON_APB),
@@ -4318,36 +4332,36 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("sbc4", "spi_tegra.3", "spi", 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc5", "spi_tegra.4", "spi", 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sbc6", "spi_tegra.5", "spi", 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
- PERIPH_CLK("sata_oob", "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sata", "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
- PERIPH_CLK("sata_cold", "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0),
- PERIPH_CLK_EX("ndflash","tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71, &tegra_nand_clk_ops),
- PERIPH_CLK("ndspeed", "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sata_oob", "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sata", "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sata_cold", "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, PERIPH_ON_APB),
+ PERIPH_CLK_EX("ndflash", "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB, &tegra_nand_clk_ops),
+ PERIPH_CLK("ndspeed", "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 50000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 102000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
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("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),
+ PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), /* max rate ??? */
+ PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("nor", "tegra-nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
- PERIPH_CLK("i2c1", "tegra-i2c.0", "i2c-div", 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c2", "tegra-i2c.1", "i2c-div", 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c3", "tegra-i2c.2", "i2c-div", 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c4", "tegra-i2c.3", "i2c-div", 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c5", "tegra-i2c.4", "i2c-div", 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
- PERIPH_CLK("i2c1-fast", "tegra-i2c.0", "i2c-fast", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("i2c2-fast", "tegra-i2c.1", "i2c-fast", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("i2c3-fast", "tegra-i2c.2", "i2c-fast", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("i2c4-fast", "tegra-i2c.3", "i2c-fast", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
- PERIPH_CLK("i2c5-fast", "tegra-i2c.4", "i2c-fast", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c1", "tegra-i2c.0", "div-clk", 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c2", "tegra-i2c.1", "div-clk", 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c3", "tegra-i2c.2", "div-clk", 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c4", "tegra-i2c.3", "div-clk", 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c5", "tegra-i2c.4", "div-clk", 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c1-fast", "tegra-i2c.0", "fast-clk", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c2-fast", "tegra-i2c.1", "fast-clk", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c3-fast", "tegra-i2c.2", "fast-clk", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c4-fast", "tegra-i2c.3", "fast-clk", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("i2c5-fast", "tegra-i2c.4", "fast-clk", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 900000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB),
PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 900000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB),
PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 900000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB),
@@ -4368,7 +4382,7 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK_EX("dtv", "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0, &tegra_dtv_clk_ops),
+ PERIPH_CLK_EX("dtv", "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, PERIPH_ON_APB, &tegra_dtv_clk_ops),
PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71),
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),
@@ -4384,7 +4398,7 @@ struct clk tegra_list_clks[] = {
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),
- PERIPH_CLK("tsensor", "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71),
+ PERIPH_CLK("tsensor", "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("actmon", "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71),
PERIPH_CLK("extern1", "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
PERIPH_CLK("extern2", "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
@@ -4392,7 +4406,7 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("i2cslow", "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
PERIPH_CLK("pcie", "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("afi", "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0),
- PERIPH_CLK("se", "se", NULL, 127, 0x42c, 625000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
+ PERIPH_CLK("se", "se", NULL, 127, 0x42c, 625000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT | PERIPH_ON_APB),
PERIPH_CLK("mselect", "mselect", NULL, 99, 0x3b4, 108000000, mux_pllp_clkm, MUX | DIV_U71),
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
@@ -4401,7 +4415,8 @@ struct clk tegra_list_clks[] = {
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),
- SHARED_CLK("wake.sclk", "wake_sclk", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
+ SHARED_CLK("wake.sclk", "wake_sclk", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
+ SHARED_CLK("cpu_mode.sclk","cpu_mode", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("mon.avp", "tegra_actmon", "avp", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("cap.sclk", "cap_sclk", NULL, &tegra_clk_sbus_cmplx, NULL, 0, SHARED_CEILING),
SHARED_CLK("floor.sclk", "floor_sclk", NULL, &tegra_clk_sbus_cmplx, NULL, 0, 0),
@@ -4437,8 +4452,11 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("epp.cbus", "tegra_gr2d", "epp", &tegra_clk_cbus, "epp", 0, 0),
SHARED_CLK("mpe.cbus", "tegra_mpe", "mpe", &tegra_clk_cbus, "mpe", 0, 0),
SHARED_CLK("vde.cbus", "tegra-avp", "vde", &tegra_clk_cbus, "vde", 0, 0),
+#ifdef CONFIG_TEGRA_SE_ON_CBUS
SHARED_CLK("se.cbus", "tegra-se", NULL, &tegra_clk_cbus, "se", 0, 0),
+#endif
SHARED_CLK("cap.cbus", "cap.cbus", NULL, &tegra_clk_cbus, NULL, 0, SHARED_CEILING),
+ SHARED_CLK("cap.profile.cbus", "profile.cbus", NULL, &tegra_clk_cbus, NULL, 0, SHARED_CEILING),
SHARED_CLK("floor.cbus", "floor.cbus", NULL, &tegra_clk_cbus, NULL, 0, 0),
};
@@ -5468,6 +5486,7 @@ void __init tegra_soc_init_clocks(void)
tegra3_init_one_clock(&tegra_clk_out_list[i]);
emc_bridge = &tegra_clk_emc_bridge;
+ cpu_mode_sclk = tegra_get_clock_by_name("cpu_mode.sclk");
/* Initialize to default */
tegra_init_cpu_edp_limits(0);
diff --git a/arch/arm/mach-tegra/tegra3_dvfs.c b/arch/arm/mach-tegra/tegra3_dvfs.c
index 5af1b44cd99c..feb69a4621ed 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-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
@@ -21,6 +21,7 @@
#include <linux/clk.h>
#include <linux/kobject.h>
#include <linux/err.h>
+#include <linux/time.h>
#include "clock.h"
#include "dvfs.h"
@@ -28,15 +29,19 @@
#include "board.h"
#include "tegra3_emc.h"
+#define CPU_MILLIVOLTS {\
+ 750, 762, 775, 787, 800, 825, 837, 850, 862, 875, 887, 900, 912, 916, 925, 937, 950, 962, 975, 987, 1000, 1007, 1012, 1025, 1037, 1050, 1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150, 1162, 1175, 1187, 1200, 1212, 1237};
+
static bool tegra_dvfs_cpu_disabled;
static bool tegra_dvfs_core_disabled;
static struct dvfs *cpu_dvfs;
-static const int cpu_millivolts[MAX_DVFS_FREQS] = {
- 800, 825, 850, 875, 900, 916, 950, 975, 1000, 1007, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1212, 1237};
+static int cpu_millivolts[MAX_DVFS_FREQS] = CPU_MILLIVOLTS;
+
+static const int cpu_millivolts_aged[MAX_DVFS_FREQS] = CPU_MILLIVOLTS;
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, 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};
@@ -54,7 +59,7 @@ static int cpu_below_core = VDD_CPU_BELOW_VDD_CORE;
static struct dvfs_rail tegra3_dvfs_rail_vdd_cpu = {
.reg_id = "vdd_cpu",
.max_millivolts = 1250,
- .min_millivolts = 800,
+ .min_millivolts = 725,
.step = VDD_SAFE_STEP,
.jmp_to_zero = true,
};
@@ -141,59 +146,59 @@ static struct dvfs_relationship tegra3_dvfs_relationships[] = {
}
static struct dvfs cpu_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 */
- 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),
+ /* Cpu voltages (mV): 750, 762, 775, 787, 800, 825, 837, 850, 862, 875, 887, 900, 912, 916, 925, 937, 950, 962, 975, 987, 1000, 1007, 1012, 1025, 1037, 1050, 1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150, 1162, 1175, 1187, 1200, 1212, 1237 */
+ CPU_DVFS("cpu_g", 0, 0, MHZ, 1, 1, 1, 1, 1, 1, 1, 684, 684, 684, 684, 817, 817, 817, 817, 817, 817, 817, 1026, 1026, 1102, 1102, 1102, 1149, 1149, 1187, 1187, 1225, 1225, 1282, 1282, 1300),
+ CPU_DVFS("cpu_g", 0, 1, MHZ, 1, 1, 1, 1, 1, 1, 1, 807, 807, 807, 807, 948, 948, 948, 948, 948, 948, 948, 1117, 1117, 1171, 1171, 1171, 1206, 1206, 1300),
+ CPU_DVFS("cpu_g", 0, 2, MHZ, 1, 1, 1, 1, 1, 1, 1, 883, 883, 883, 883, 1039, 1039, 1039, 1039, 1039, 1039, 1039, 1178, 1178, 1206, 1206, 1206, 1300),
+ CPU_DVFS("cpu_g", 0, 3, MHZ, 1, 1, 1, 1, 1, 1, 1, 931, 931, 931, 931, 1102, 1102, 1102, 1102, 1102, 1102, 1102, 1216, 1216, 1300, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 1, 0, MHZ, 1, 1, 1, 1, 460, 460, 460, 550, 550, 550, 550, 680, 680, 680, 680, 680, 680, 680, 820, 820, 970, 970, 970, 1040, 1040, 1080, 1080, 1150, 1150, 1200, 1200, 1280, 1280, 1300),
+ CPU_DVFS("cpu_g", 1, 1, MHZ, 1, 1, 1, 1, 480, 480, 480, 650, 650, 650, 650, 780, 780, 780, 780, 780, 780, 780, 990, 990, 1040, 1040, 1040, 1100, 1100, 1200, 1200, 1300),
+ CPU_DVFS("cpu_g", 1, 2, MHZ, 1, 1, 1, 1, 520, 520, 520, 700, 700, 700, 700, 860, 860, 860, 860, 860, 860, 860, 1050, 1050, 1150, 1150, 1150, 1200, 1200, 1300),
+ CPU_DVFS("cpu_g", 1, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1300),
+
+ CPU_DVFS("cpu_g", 2, 1, MHZ, 1, 1, 1, 1, 480, 480, 480, 650, 650, 650, 650, 780, 780, 780, 780, 780, 780, 780, 990, 990, 1040, 1040, 1040, 1100, 1100, 1200, 1200, 1250, 1250, 1300, 1300, 1330, 1330, 1400),
+ CPU_DVFS("cpu_g", 2, 2, MHZ, 1, 1, 1, 1, 520, 520, 520, 700, 700, 700, 700, 860, 860, 860, 860, 860, 860, 860, 1050, 1050, 1150, 1150, 1150, 1200, 1200, 1280, 1280, 1300, 1300, 1350, 1350, 1400),
+ CPU_DVFS("cpu_g", 2, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1280, 1280, 1300, 1300, 1350, 1350, 1400),
+
+ CPU_DVFS("cpu_g", 3, 1, MHZ, 1, 1, 1, 1, 480, 480, 480, 650, 650, 650, 650, 780, 780, 780, 780, 780, 780, 780, 990, 990, 1040, 1040, 1040, 1100, 1100, 1200, 1200, 1250, 1250, 1300, 1300, 1330, 1330, 1400),
+ CPU_DVFS("cpu_g", 3, 2, MHZ, 1, 1, 1, 1, 520, 520, 520, 700, 700, 700, 700, 860, 860, 860, 860, 860, 860, 860, 1050, 1050, 1150, 1150, 1150, 1200, 1200, 1280, 1280, 1300, 1300, 1350, 1350, 1400),
+ CPU_DVFS("cpu_g", 3, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1280, 1280, 1300, 1300, 1350, 1350, 1400),
+
+ CPU_DVFS("cpu_g", 4, 0, MHZ, 1, 1, 1, 1, 460, 460, 460, 550, 550, 550, 550, 680, 680, 680, 680, 680, 680, 680, 820, 820, 970, 970, 970, 1040, 1040, 1080, 1080, 1150, 1150, 1200, 1200, 1240, 1240, 1280, 1280, 1320, 1320, 1360, 1360, 1500),
+ CPU_DVFS("cpu_g", 4, 1, MHZ, 1, 1, 1, 1, 480, 480, 480, 650, 650, 650, 650, 780, 780, 780, 780, 780, 780, 780, 990, 990, 1040, 1040, 1040, 1100, 1100, 1200, 1200, 1250, 1250, 1300, 1300, 1330, 1330, 1360, 1360, 1400, 1400, 1500),
+ CPU_DVFS("cpu_g", 4, 2, MHZ, 1, 1, 1, 1, 520, 520, 520, 700, 700, 700, 700, 860, 860, 860, 860, 860, 860, 860, 1050, 1050, 1150, 1150, 1150, 1200, 1200, 1280, 1280, 1300, 1300, 1340, 1340, 1380, 1380, 1500),
+ CPU_DVFS("cpu_g", 4, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1280, 1280, 1330, 1330, 1370, 1370, 1400, 1400, 1500),
+
+ CPU_DVFS("cpu_g", 5, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1280, 1280, 1330, 1330, 1370, 1370, 1400, 1400, 1470, 1470, 1500, 1500, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 5, 4, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 940, 940, 940, 940, 940, 940, 940, 1160, 1160, 1240, 1240, 1240, 1280, 1280, 1360, 1360, 1390, 1390, 1470, 1470, 1500, 1500, 1520, 1520, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 6, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1280, 1280, 1330, 1330, 1370, 1370, 1400, 1400, 1470, 1470, 1500, 1500, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 6, 4, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 940, 940, 940, 940, 940, 940, 940, 1160, 1160, 1240, 1240, 1240, 1280, 1280, 1360, 1360, 1390, 1390, 1470, 1470, 1500, 1500, 1520, 1520, 1520, 1520, 1590, 1700),
+
+ CPU_DVFS("cpu_g", 7, 0, MHZ, 1, 1, 1, 1, 460, 460, 460, 550, 550, 550, 550, 680, 680, 680, 680, 680, 680, 680, 820, 820, 970, 970, 970, 1040, 1040, 1080, 1080, 1150, 1150, 1200, 1200, 1280, 1280, 1300),
+ CPU_DVFS("cpu_g", 7, 1, MHZ, 1, 1, 1, 1, 480, 480, 480, 650, 650, 650, 650, 780, 780, 780, 780, 780, 780, 780, 990, 990, 1040, 1040, 1040, 1100, 1100, 1200, 1200, 1300),
+ CPU_DVFS("cpu_g", 7, 2, MHZ, 1, 1, 1, 1, 520, 520, 520, 700, 700, 700, 700, 860, 860, 860, 860, 860, 860, 860, 1050, 1050, 1150, 1150, 1150, 1200, 1200, 1300),
+ CPU_DVFS("cpu_g", 7, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1300),
+ CPU_DVFS("cpu_g", 7, 4, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 940, 940, 940, 940, 940, 940, 940, 1160, 1160, 1300, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 8, 0, MHZ, 1, 1, 1, 1, 460, 460, 460, 550, 550, 550, 550, 680, 680, 680, 680, 680, 680, 680, 820, 820, 970, 970, 970, 1040, 1040, 1080, 1080, 1150, 1150, 1200, 1200, 1280, 1280, 1300),
+ CPU_DVFS("cpu_g", 8, 1, MHZ, 1, 1, 1, 1, 480, 480, 480, 650, 650, 650, 650, 780, 780, 780, 780, 780, 780, 780, 990, 990, 1040, 1040, 1040, 1100, 1100, 1200, 1200, 1300),
+ CPU_DVFS("cpu_g", 8, 2, MHZ, 1, 1, 1, 1, 520, 520, 520, 700, 700, 700, 700, 860, 860, 860, 860, 860, 860, 860, 1050, 1050, 1150, 1150, 1150, 1200, 1200, 1300),
+ CPU_DVFS("cpu_g", 8, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1300),
+ CPU_DVFS("cpu_g", 8, 4, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 940, 940, 940, 940, 940, 940, 940, 1160, 1160, 1300, 1300, 1300),
+
+ CPU_DVFS("cpu_g", 9, -1, MHZ, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 10, -1, MHZ, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 11, -1, MHZ, 1, 1, 1, 1, 1, 1, 1, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+ CPU_DVFS("cpu_g", 15, -1, MHZ, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900),
+
+ CPU_DVFS("cpu_g", 12, 3, MHZ, 1, 475, 475, 475, 475, 620, 620, 620, 620, 760, 760, 760, 760, 760, 910, 910, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1500, 1500, 1700),
+ CPU_DVFS("cpu_g", 12, 4, MHZ, 475, 475, 475, 475, 475, 620, 620, 620, 760, 760, 760, 760, 910, 910, 910, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1700),
+
+ CPU_DVFS("cpu_g", 13, 3, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 910, 910, 910, 910, 910, 910, 910, 1150, 1150, 1230, 1230, 1230, 1280, 1280, 1330, 1330, 1370, 1370, 1400, 1400, 1470, 1470, 1500, 1500, 1500, 1500, 1540, 1540, 1700),
+ CPU_DVFS("cpu_g", 13, 4, MHZ, 1, 1, 1, 1, 550, 550, 550, 770, 770, 770, 770, 940, 940, 940, 940, 940, 940, 940, 1160, 1160, 1240, 1240, 1240, 1280, 1280, 1360, 1360, 1390, 1390, 1470, 1470, 1500, 1500, 1520, 1520, 1520, 1520, 1590, 1700),
/*
* "Safe entry" to be used when no match for chip speedo, process
@@ -203,7 +208,20 @@ static struct dvfs cpu_dvfs_table[] = {
};
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 */
+ /* Cpu voltages (mV): 750, 762, 775, 787, 800, 825, 837, 850, 862, 875, 887, 900, 912, 916, 925, 937, 950, 962, 975, 987, 1000, 1007, 1012, 1025, 1037, 1050, 1062, 1075, 1087, 1100, 1112, 1125, 1137, 1150, 1162, 1175, 1187, 1200, 1212, 1237*/
+ CPU_DVFS("cpu_0", 4, 0, MHZ, 1, 1, 1, 475, 475, 475, 475, 640, 640, 640, 760, 760, 760, 760, 860, 860, 860, 860, 860, 1000, 1000, 1000, 1000, 1100, 1100, 1100, 1100, 1200, 1200, 1200, 1200, 1200, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1500),
+ CPU_DVFS("cpu_0", 4, 1, MHZ, 1, 475, 475, 475, 475, 640, 640, 640, 760, 760, 760, 860, 860, 860, 860, 860, 1000, 1000, 1000, 1100, 1100, 1100, 1100, 1100, 1200, 1200, 1200, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1400, 1400, 1500),
+ CPU_DVFS("cpu_0", 4, 2, MHZ, 475, 475, 475, 640, 640, 640, 760, 760, 760, 860, 860, 860, 1000, 1000, 1000, 1000, 1000, 1100, 1100, 1200, 1200, 1200, 1200, 1200, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1400, 1500),
+ CPU_DVFS("cpu_0", 4, 3, MHZ, 475, 475, 640, 640, 640, 760, 760, 860, 860, 860, 860, 1000, 1000, 1000, 1100, 1100, 1100, 1100, 1200, 1200, 1200, 1200, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1400, 1500),
+
+ CPU_DVFS("cpu_0", 5, 3, MHZ, 475, 475, 620, 620, 620, 760, 760, 760, 910, 910, 910, 1000, 1000, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1700),
+ CPU_DVFS("cpu_0", 5, 4, MHZ, 475, 620, 620, 620, 760, 760, 760, 910, 910, 1000, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1700),
+
+ CPU_DVFS("cpu_0", 6, 3, MHZ, 475, 475, 620, 620, 620, 760, 760, 760, 910, 910, 910, 1000, 1000, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1700),
+ CPU_DVFS("cpu_0", 6, 4, MHZ, 475, 620, 620, 620, 760, 760, 760, 910, 910, 1000, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1700),
+
+ CPU_DVFS("cpu_0", 12, 3, MHZ, 475, 475, 620, 620, 620, 760, 760, 760, 910, 910, 910, 1000, 1000, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1700),
+ CPU_DVFS("cpu_0", 12, 4, MHZ, 475, 620, 620, 620, 760, 760, 760, 910, 910, 1000, 1000, 1000, 1000, 1000, 1000, 1150, 1150, 1150, 1150, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1500, 1500, 1500, 1500, 1500, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1700),
};
#define CORE_DVFS(_clk_name, _speedo_id, _auto, _mult, _freqs...) \
@@ -305,6 +323,7 @@ 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("sdmmc4", -1, 1, KHZ, 51000, 102000, 102000, 102000, 102000, 102000, 102000, 102000, 102000),
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),
@@ -618,6 +637,41 @@ static int __init get_core_nominal_mv_index(int speedo_id)
return (i - 1);
}
+static void tegra_adjust_cpu_mvs(int mvs)
+{
+ int i;
+
+ BUG_ON(ARRAY_SIZE(cpu_millivolts) != ARRAY_SIZE(cpu_millivolts_aged));
+
+ for (i = 0; i < ARRAY_SIZE(cpu_millivolts); i++)
+ cpu_millivolts[i] = cpu_millivolts_aged[i] - mvs;
+}
+
+/**
+ * Adjust VDD_CPU to offset aging.
+ * 25mV for 1st year
+ * 12mV for 2nd and 3rd year
+ * 0mV for 4th year onwards
+ */
+void tegra_dvfs_age_cpu(int cur_linear_age)
+{
+ int chip_linear_age;
+ int chip_life;
+ chip_linear_age = tegra_get_age();
+ chip_life = cur_linear_age - chip_linear_age;
+
+ /*For T37 and AP37*/
+ if (tegra_cpu_speedo_id() == 12 || tegra_cpu_speedo_id() == 13) {
+ if (chip_linear_age <= 0) {
+ return;
+ } else if (chip_life <= 12) {
+ tegra_adjust_cpu_mvs(25);
+ } else if (chip_life <= 36) {
+ tegra_adjust_cpu_mvs(13);
+ }
+ }
+}
+
void __init tegra_soc_init_dvfs(void)
{
int cpu_speedo_id = tegra_cpu_speedo_id();
@@ -692,19 +746,23 @@ void __init tegra_soc_init_dvfs(void)
tegra_dvfs_core_disabled ? "disabled" : "enabled");
}
-void tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
- bool before_clk_update)
+int tegra_cpu_dvfs_alter(int edp_thermal_index, const cpumask_t *cpus,
+ bool before_clk_update, int cpu_event)
{
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) {
+ if (cpu_event || (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");
+ if (ret) {
+ pr_err("tegra dvfs: failed to set alternative dvfs on "
+ "%u %s CPUs\n", n, cpu_warm ? "warm" : "cold");
+ return ret;
+ }
}
+ return 0;
}
int tegra_dvfs_rail_disable_prepare(struct dvfs_rail *rail)
@@ -762,6 +820,8 @@ static struct core_cap tegra3_core_cap;
static struct core_cap kdvfs_core_cap;
static struct core_cap user_core_cap;
+static struct core_cap user_cbus_cap;
+
static struct kobject *cap_kobj;
/* Arranged in order required for enabling/lowering the cap */
@@ -880,14 +940,91 @@ core_cap_level_store(struct kobject *kobj, struct kobj_attribute *attr,
return count;
}
+static void cbus_cap_update(void)
+{
+ static struct clk *cbus_cap;
+
+ if (!cbus_cap) {
+ cbus_cap = tegra_get_clock_by_name("cap.profile.cbus");
+ if (!cbus_cap) {
+ WARN_ONCE(1, "tegra3_dvfs: cbus profiling is not supported");
+ return;
+ }
+ }
+
+ if (user_cbus_cap.refcnt)
+ clk_set_rate(cbus_cap, user_cbus_cap.level);
+ else
+ clk_set_rate(cbus_cap, clk_get_max_rate(cbus_cap));
+}
+
+static ssize_t
+cbus_cap_state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", user_cbus_cap.refcnt ? 1 : 0);
+}
+static ssize_t
+cbus_cap_state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int state;
+
+ if (sscanf(buf, "%d", &state) != 1)
+ return -1;
+
+ mutex_lock(&core_cap_lock);
+
+ if (state) {
+ user_cbus_cap.refcnt++;
+ if (user_cbus_cap.refcnt == 1)
+ cbus_cap_update();
+ } else if (user_cbus_cap.refcnt) {
+ user_cbus_cap.refcnt--;
+ if (user_cbus_cap.refcnt == 0)
+ cbus_cap_update();
+ }
+
+ mutex_unlock(&core_cap_lock);
+ return count;
+}
+
+static ssize_t
+cbus_cap_level_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", user_cbus_cap.level);
+}
+static ssize_t
+cbus_cap_level_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int level;
+
+ if (sscanf(buf, "%d", &level) != 1)
+ return -1;
+
+ mutex_lock(&core_cap_lock);
+ user_cbus_cap.level = level;
+ cbus_cap_update();
+ mutex_unlock(&core_cap_lock);
+ return count;
+}
+
static struct kobj_attribute cap_state_attribute =
__ATTR(core_cap_state, 0644, core_cap_state_show, core_cap_state_store);
static struct kobj_attribute cap_level_attribute =
__ATTR(core_cap_level, 0644, core_cap_level_show, core_cap_level_store);
+static struct kobj_attribute cbus_state_attribute =
+ __ATTR(cbus_cap_state, 0644, cbus_cap_state_show, cbus_cap_state_store);
+static struct kobj_attribute cbus_level_attribute =
+ __ATTR(cbus_cap_level, 0644, cbus_cap_level_show, cbus_cap_level_store);
const struct attribute *cap_attributes[] = {
&cap_state_attribute.attr,
&cap_level_attribute.attr,
+ &cbus_state_attribute.attr,
+ &cbus_level_attribute.attr,
NULL,
};
diff --git a/arch/arm/mach-tegra/tegra3_emc.c b/arch/arm/mach-tegra/tegra3_emc.c
index a138091d9197..4c06bf91ab1f 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) 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
@@ -33,6 +33,7 @@
#include <asm/cacheflush.h>
#include <mach/iomap.h>
+#include <mach/latency_allowance.h>
#include "clock.h"
#include "dvfs.h"
@@ -46,6 +47,7 @@ static bool emc_enable;
module_param(emc_enable, bool, 0644);
u8 tegra_emc_bw_efficiency = 35;
+u8 tegra_emc_bw_efficiency_boost = 45;
#define EMC_MIN_RATE_DDR3 25500000
#define EMC_STATUS_UPDATE_TIMEOUT 100
@@ -1017,6 +1019,31 @@ static struct notifier_block tegra_emc_resume_nb = {
.priority = -1,
};
+static int tegra_emc_get_table_ns_per_tick(unsigned int emc_rate,
+ unsigned int table_tick_len)
+{
+ unsigned int ns_per_tick = 0;
+ unsigned int mc_period_10ns = 0;
+ unsigned int reg;
+
+ reg = mc_readl(MC_EMEM_ARB_MISC0) & MC_EMEM_ARB_MISC0_EMC_SAME_FREQ;
+
+ mc_period_10ns = ((reg ? (NSEC_PER_MSEC * 10) : (20 * NSEC_PER_MSEC)) /
+ (emc_rate));
+ ns_per_tick = ((table_tick_len & MC_EMEM_ARB_CFG_CYCLE_MASK)
+ * mc_period_10ns) / (10 *
+ (1 + ((table_tick_len & MC_EMEM_ARB_CFG_EXTRA_TICK_MASK)
+ >> MC_EMEM_ARB_CFG_EXTRA_TICK_SHIFT)));
+
+ /* round new_ns_per_tick to 30/60 */
+ if (ns_per_tick < 45)
+ ns_per_tick = 30;
+ else
+ ns_per_tick = 60;
+
+ return ns_per_tick;
+}
+
void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
{
int i, mv;
@@ -1024,6 +1051,8 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
bool max_entry = false;
unsigned long boot_rate, max_rate;
struct clk *cbus = tegra_get_clock_by_name("cbus");
+ unsigned int ns_per_tick = 0;
+ unsigned int cur_ns_per_tick = 0;
emc_stats.clkchange_count = 0;
spin_lock_init(&emc_stats.spinlock);
@@ -1084,6 +1113,19 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
if (table_rate == max_rate)
max_entry = true;
+
+ cur_ns_per_tick = tegra_emc_get_table_ns_per_tick(table_rate,
+ table[i].burst_regs[MC_EMEM_ARB_CFG_INDEX]);
+
+ if (ns_per_tick == 0) {
+ ns_per_tick = cur_ns_per_tick;
+ } else if (ns_per_tick != cur_ns_per_tick) {
+ pr_err("tegra: invalid EMC DFS table: "
+ "mismatched DFS tick lengths "
+ "within table!\n");
+ ns_per_tick = 0;
+ return;
+ }
}
/* Validate EMC rate and voltage limits */
@@ -1093,6 +1135,8 @@ void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
return;
}
+ tegra_latency_allowance_update_tick_length(ns_per_tick);
+
tegra_emc_table = table;
adjust_emc_dvfs_table(tegra_emc_table, tegra_emc_table_size);
@@ -1379,6 +1423,22 @@ static int efficiency_set(void *data, u64 val)
DEFINE_SIMPLE_ATTRIBUTE(efficiency_fops, efficiency_get,
efficiency_set, "%llu\n");
+static int efficiency_boost_get(void *data, u64 *val)
+{
+ *val = tegra_emc_bw_efficiency_boost;
+ return 0;
+}
+static int efficiency_boost_set(void *data, u64 val)
+{
+ tegra_emc_bw_efficiency_boost = (val > 100) ? 100 : val;
+ if (emc)
+ tegra_clk_shared_bus_update(emc);
+
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(efficiency_boost_fops, efficiency_boost_get,
+ efficiency_boost_set, "%llu\n");
+
static int __init tegra_emc_debug_init(void)
{
if (!tegra_emc_table)
@@ -1408,6 +1468,10 @@ static int __init tegra_emc_debug_init(void)
emc_debugfs_root, NULL, &efficiency_fops))
goto err_out;
+ if (!debugfs_create_file("efficiency_boost", S_IRUGO | S_IWUSR,
+ emc_debugfs_root, NULL, &efficiency_boost_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 f59654295ba4..43ef636c613f 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) 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
@@ -28,6 +28,7 @@
#define TEGRA_EMC_BRIDGE_MVOLTS_MIN 1200
extern u8 tegra_emc_bw_efficiency;
+extern u8 tegra_emc_bw_efficiency_boost;
struct tegra_emc_table {
u8 rev;
@@ -266,6 +267,10 @@ enum {
#define MC_EMEM_ADR_CFG 0x54
#define MC_EMEM_ARB_CFG 0x90
+#define MC_EMEM_ARB_CFG_CYCLE_MASK 0x1ff
+#define MC_EMEM_ARB_CFG_EXTRA_TICK_SHIFT 16
+#define MC_EMEM_ARB_CFG_EXTRA_TICK_MASK \
+ (0x1f << MC_EMEM_ARB_CFG_EXTRA_TICK_SHIFT)
#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_SHIFT 0
#define MC_EMEM_ARB_OUTSTANDING_REQ_MAX_MASK \
@@ -294,6 +299,43 @@ enum {
#define MC_EMEM_ARB_OVERRIDE 0xe8
#define MC_EMEM_ARB_OVERRIDE_EACK_MASK (0x3 << 0)
#define MC_TIMING_CONTROL 0xfc
+#define MC_LATENCY_ALLOWANCE_AFI 0x2e0
+#define MC_LATENCY_ALLOWANCE_AVPC 0x2e4
+#define MC_LATENCY_ALLOWANCE_DC_0 0x2e8
+#define MC_LATENCY_ALLOWANCE_DC_1 0x2ec
+#define MC_LATENCY_ALLOWANCE_DC_2 0x2f0
+#define MC_LATENCY_ALLOWANCE_DCB_0 0x2f4
+#define MC_LATENCY_ALLOWANCE_DCB_1 0x2f8
+#define MC_LATENCY_ALLOWANCE_DCB_2 0x2fc
+#define MC_LATENCY_ALLOWANCE_EPP_0 0x300
+#define MC_LATENCY_ALLOWANCE_EPP_1 0x304
+#define MC_LATENCY_ALLOWANCE_G2_0 0x308
+#define MC_LATENCY_ALLOWANCE_G2_1 0x30c
+#define MC_LATENCY_ALLOWANCE_HC_0 0x310
+#define MC_LATENCY_ALLOWANCE_HC_1 0x314
+#define MC_LATENCY_ALLOWANCE_HDA 0x318
+#define MC_LATENCY_ALLOWANCE_ISP 0x31c
+#define MC_LATENCY_ALLOWANCE_MPCORE 0x320
+#define MC_LATENCY_ALLOWANCE_MPCORELP 0x324
+#define MC_LATENCY_ALLOWANCE_MPE_0 0x328
+#define MC_LATENCY_ALLOWANCE_MPE_1 0x32c
+#define MC_LATENCY_ALLOWANCE_MPE_2 0x330
+#define MC_LATENCY_ALLOWANCE_NV_0 0x334
+#define MC_LATENCY_ALLOWANCE_NV_1 0x338
+#define MC_LATENCY_ALLOWANCE_NV2_0 0x33c
+#define MC_LATENCY_ALLOWANCE_NV2_1 0x340
+#define MC_LATENCY_ALLOWANCE_PPCS_0 0x344
+#define MC_LATENCY_ALLOWANCE_PPCS_1 0x348
+#define MC_LATENCY_ALLOWANCE_PTC 0x34c
+#define MC_LATENCY_ALLOWANCE_SATA 0x350
+#define MC_LATENCY_ALLOWANCE_VDE_0 0x354
+#define MC_LATENCY_ALLOWANCE_VDE_1 0x358
+#define MC_LATENCY_ALLOWANCE_VDE_2 0x35c
+#define MC_LATENCY_ALLOWANCE_VDE_3 0x360
+#define MC_LATENCY_ALLOWANCE_VI_0 0x364
+#define MC_LATENCY_ALLOWANCE_VI_1 0x368
+#define MC_LATENCY_ALLOWANCE_VI_2 0x36c
+
#define MC_RESERVED_RSV 0x3fc
#endif
diff --git a/arch/arm/mach-tegra/tegra3_la_priv.h b/arch/arm/mach-tegra/tegra3_la_priv.h
new file mode 100644
index 000000000000..2a39ea41b6f5
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra3_la_priv.h
@@ -0,0 +1,226 @@
+/*
+ * arch/arm/mach-tegra/tegra3_la_priv.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_TEGRA3_LA_PRIV_H_
+#define _MACH_TEGRA_TEGRA3_LA_PRIV_H_
+
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+
+#define MC_LA_AFI_0 0x2e0
+#define MC_LA_AVPC_ARM7_0 0x2e4
+#define MC_LA_DC_0 0x2e8
+#define MC_LA_DC_1 0x2ec
+#define MC_LA_DC_2 0x2f0
+#define MC_LA_DCB_0 0x2f4
+#define MC_LA_DCB_1 0x2f8
+#define MC_LA_DCB_2 0x2fc
+#define MC_LA_EPP_0 0x300
+#define MC_LA_EPP_1 0x304
+#define MC_LA_G2_0 0x308
+#define MC_LA_G2_1 0x30c
+#define MC_LA_HC_0 0x310
+#define MC_LA_HC_1 0x314
+#define MC_LA_HDA_0 0x318
+#define MC_LA_ISP_0 0x31C
+#define MC_LA_MPCORE_0 0x320
+#define MC_LA_MPCORELP_0 0x324
+#define MC_LA_MPE_0 0x328
+#define MC_LA_MPE_1 0x32c
+#define MC_LA_MPE_2 0x330
+#define MC_LA_NV_0 0x334
+#define MC_LA_NV_1 0x338
+#define MC_LA_NV2_0 0x33c
+#define MC_LA_NV2_1 0x340
+#define MC_LA_PPCS_0 0x344
+#define MC_LA_PPCS_1 0x348
+#define MC_LA_PTC_0 0x34c
+#define MC_LA_SATA_0 0x350
+#define MC_LA_VDE_0 0x354
+#define MC_LA_VDE_1 0x358
+#define MC_LA_VDE_2 0x35c
+#define MC_LA_VDE_3 0x360
+#define MC_LA_VI_0 0x364
+#define MC_LA_VI_1 0x368
+#define MC_LA_VI_2 0x36c
+
+#define MC_ARB_OVERRIDE 0xe8
+#define GLOBAL_LATENCY_SCALING_ENABLE_BIT 7
+
+#define DS_DISP_MCCIF_DISPLAY0A_HYST (0x481 * 4)
+#define DS_DISP_MCCIF_DISPLAY0B_HYST (0x482 * 4)
+#define DS_DISP_MCCIF_DISPLAY0C_HYST (0x483 * 4)
+#define DS_DISP_MCCIF_DISPLAY1B_HYST (0x484 * 4)
+
+#define DS_DISP_MCCIF_DISPLAY0AB_HYST (0x481 * 4)
+#define DS_DISP_MCCIF_DISPLAY0BB_HYST (0x482 * 4)
+#define DS_DISP_MCCIF_DISPLAY0CB_HYST (0x483 * 4)
+#define DS_DISP_MCCIF_DISPLAY1BB_HYST (0x484 * 4)
+
+#define VI_MCCIF_VIWSB_HYST (0x9a * 4)
+#define VI_MCCIF_VIWU_HYST (0x9b * 4)
+#define VI_MCCIF_VIWV_HYST (0x9c * 4)
+#define VI_MCCIF_VIWY_HYST (0x9d * 4)
+
+#define VI_TIMEOUT_WOCAL_VI (0x70 * 4)
+#define VI_RESERVE_3 (0x97 * 4)
+#define VI_RESERVE_4 (0x98 * 4)
+
+/*
+ * The rule for getting the fifo_size_in_atoms is:
+ * 1.If REORDER_DEPTH exists, use it(default is overridden).
+ * 2.Else if (write_client) use RFIFO_DEPTH.
+ * 3.Else (read client) use RDFIFO_DEPTH.
+ * Multiply the value by 2 for wide clients.
+ * A client is wide, if CMW is larger than MW.
+ * Refer to project.h file.
+ */
+struct la_client_info la_info_array[] = {
+ LA_INFO(32, 150, AFI_0, 7 : 0, AFIR, false),
+ LA_INFO(32, 150, AFI_0, 23 : 16, AFIW, false),
+ LA_INFO(2, 150, AVPC_ARM7_0, 7 : 0, AVPC_ARM7R, false),
+ LA_INFO(2, 150, AVPC_ARM7_0, 23 : 16, AVPC_ARM7W, false),
+ LA_INFO(128, 1050, DC_0, 7 : 0, DISPLAY_0A, true),
+ LA_INFO(64, 1050, DC_0, 23 : 16, DISPLAY_0B, true),
+ LA_INFO(128, 1050, DC_1, 7 : 0, DISPLAY_0C, true),
+ LA_INFO(64, 1050, DC_1, 23 : 16, DISPLAY_1B, true),
+ LA_INFO(2, 1050, DC_2, 7 : 0, DISPLAY_HC, false),
+ LA_INFO(128, 1050, DCB_0, 7 : 0, DISPLAY_0AB, true),
+ LA_INFO(64, 1050, DCB_0, 23 : 16, DISPLAY_0BB, true),
+ LA_INFO(128, 1050, DCB_1, 7 : 0, DISPLAY_0CB, true),
+ LA_INFO(64, 1050, DCB_1, 23 : 16, DISPLAY_1BB, true),
+ LA_INFO(2, 1050, DCB_2, 7 : 0, DISPLAY_HCB, false),
+ LA_INFO(8, 150, EPP_0, 7 : 0, EPPUP, false),
+ LA_INFO(64, 150, EPP_0, 23 : 16, EPPU, false),
+ LA_INFO(64, 150, EPP_1, 7 : 0, EPPV, false),
+ LA_INFO(64, 150, EPP_1, 23 : 16, EPPY, false),
+ LA_INFO(64, 150, G2_0, 7 : 0, G2PR, false),
+ LA_INFO(64, 150, G2_0, 23 : 16, G2SR, false),
+ LA_INFO(48, 150, G2_1, 7 : 0, G2DR, false),
+ LA_INFO(128, 150, G2_1, 23 : 16, G2DW, false),
+ LA_INFO(16, 150, HC_0, 7 : 0, HOST1X_DMAR, false),
+ LA_INFO(8, 150, HC_0, 23 : 16, HOST1XR, false),
+ LA_INFO(32, 150, HC_1, 7 : 0, HOST1XW, false),
+ LA_INFO(16, 150, HDA_0, 7 : 0, HDAR, false),
+ LA_INFO(16, 150, HDA_0, 23 : 16, HDAW, false),
+ LA_INFO(64, 150, ISP_0, 7 : 0, ISPW, false),
+ LA_INFO(14, 150, MPCORE_0, 7 : 0, MPCORER, false),
+ LA_INFO(24, 150, MPCORE_0, 23 : 16, MPCOREW, false),
+ LA_INFO(14, 150, MPCORELP_0, 7 : 0, MPCORE_LPR, false),
+ LA_INFO(24, 150, MPCORELP_0, 23 : 16, MPCORE_LPW, false),
+ LA_INFO(8, 150, MPE_0, 7 : 0, MPE_UNIFBR, false),
+ LA_INFO(2, 150, MPE_0, 23 : 16, MPE_IPRED, false),
+ LA_INFO(64, 150, MPE_1, 7 : 0, MPE_AMEMRD, false),
+ LA_INFO(8, 150, MPE_1, 23 : 16, MPE_CSRD, false),
+ LA_INFO(8, 150, MPE_2, 7 : 0, MPE_UNIFBW, false),
+ LA_INFO(8, 150, MPE_2, 23 : 16, MPE_CSWR, false),
+ LA_INFO(96, 150, NV_0, 7 : 0, FDCDRD, false),
+ LA_INFO(64, 150, NV_0, 23 : 16, IDXSRD, false),
+ LA_INFO(64, 150, NV_1, 7 : 0, TEXSRD, false),
+ LA_INFO(96, 150, NV_1, 23 : 16, FDCDWR, false),
+ LA_INFO(96, 150, NV2_0, 7 : 0, FDCDRD2, false),
+ LA_INFO(64, 150, NV2_0, 23 : 16, IDXSRD2, false),
+ LA_INFO(64, 150, NV2_1, 7 : 0, TEXSRD2, false),
+ LA_INFO(96, 150, NV2_1, 23 : 16, FDCDWR2, false),
+ LA_INFO(2, 150, PPCS_0, 7 : 0, PPCS_AHBDMAR, false),
+ LA_INFO(8, 150, PPCS_0, 23 : 16, PPCS_AHBSLVR, false),
+ LA_INFO(2, 150, PPCS_1, 7 : 0, PPCS_AHBDMAW, false),
+ LA_INFO(4, 150, PPCS_1, 23 : 16, PPCS_AHBSLVW, false),
+ LA_INFO(2, 150, PTC_0, 7 : 0, PTCR, false),
+ LA_INFO(32, 150, SATA_0, 7 : 0, SATAR, false),
+ LA_INFO(32, 150, SATA_0, 23 : 16, SATAW, false),
+ LA_INFO(8, 150, VDE_0, 7 : 0, VDE_BSEVR, false),
+ LA_INFO(4, 150, VDE_0, 23 : 16, VDE_MBER, false),
+ LA_INFO(16, 150, VDE_1, 7 : 0, VDE_MCER, false),
+ LA_INFO(16, 150, VDE_1, 23 : 16, VDE_TPER, false),
+ LA_INFO(4, 150, VDE_2, 7 : 0, VDE_BSEVW, false),
+ LA_INFO(16, 150, VDE_2, 23 : 16, VDE_DBGW, false),
+ LA_INFO(2, 150, VDE_3, 7 : 0, VDE_MBEW, false),
+ LA_INFO(16, 150, VDE_3, 23 : 16, VDE_TPMW, false),
+ LA_INFO(8, 1050, VI_0, 7 : 0, VI_RUV, false),
+ LA_INFO(64, 1050, VI_0, 23 : 16, VI_WSB, true),
+ LA_INFO(64, 1050, VI_1, 7 : 0, VI_WU, true),
+ LA_INFO(64, 1050, VI_1, 23 : 16, VI_WV, true),
+ LA_INFO(64, 1050, VI_2, 7 : 0, VI_WY, true),
+
+/* end of list. */
+ LA_INFO(0, 0, AFI_0, 0 : 0, MAX_ID, false)
+};
+
+#define DISP1_RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_DISPLAY_BASE) + DS_DISP_MCCIF_##r##_HYST)
+#define DISP2_RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_DISPLAY2_BASE) + DS_DISP_MCCIF_##r##_HYST)
+
+#define DISP_SCALING_REG_INFO(id, r, ra) \
+ { \
+ ID(id), \
+ ra(r), MASK(15 : 8), SHIFT(15 : 8), \
+ ra(r), MASK(23 : 16), SHIFT(15 : 8), \
+ ra(r), MASK(7 : 0), SHIFT(15 : 8) \
+ }
+
+struct la_scaling_reg_info disp_info[] = {
+ DISP_SCALING_REG_INFO(DISPLAY_0A, DISPLAY0A, DISP1_RA),
+ DISP_SCALING_REG_INFO(DISPLAY_0B, DISPLAY0B, DISP1_RA),
+ DISP_SCALING_REG_INFO(DISPLAY_0C, DISPLAY0C, DISP1_RA),
+ DISP_SCALING_REG_INFO(DISPLAY_1B, DISPLAY1B, DISP1_RA),
+ DISP_SCALING_REG_INFO(MAX_ID, DISPLAY1B, DISP1_RA), /*dummy entry*/
+ DISP_SCALING_REG_INFO(DISPLAY_0AB, DISPLAY0AB, DISP2_RA),
+ DISP_SCALING_REG_INFO(DISPLAY_0BB, DISPLAY0BB, DISP2_RA),
+ DISP_SCALING_REG_INFO(DISPLAY_0CB, DISPLAY0CB, DISP2_RA),
+ DISP_SCALING_REG_INFO(DISPLAY_1BB, DISPLAY1BB, DISP2_RA),
+};
+
+#define VI_TH_RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_MCCIF_##r##_HYST)
+#define VI_TM_RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_TIMEOUT_WOCAL_VI)
+#define VI_TL_RA(r) \
+ ((u32)IO_ADDRESS(TEGRA_VI_BASE) + VI_RESERVE_##r)
+
+struct la_scaling_reg_info vi_info[] = {
+ {
+ ID(VI_WSB),
+ VI_TL_RA(4), MASK(7 : 0), SHIFT(7 : 0),
+ VI_TM_RA(0), MASK(7 : 0), SHIFT(7 : 0),
+ VI_TH_RA(VIWSB), MASK(7 : 0), SHIFT(7 : 0)
+ },
+ {
+ ID(VI_WU),
+ VI_TL_RA(3), MASK(15 : 8), SHIFT(15 : 8),
+ VI_TM_RA(0), MASK(15 : 8), SHIFT(15 : 8),
+ VI_TH_RA(VIWU), MASK(7 : 0), SHIFT(7 : 0)
+ },
+ {
+ ID(VI_WV),
+ VI_TL_RA(3), MASK(7 : 0), SHIFT(7 : 0),
+ VI_TM_RA(0), MASK(23 : 16), SHIFT(23 : 16),
+ VI_TH_RA(VIWV), MASK(7 : 0), SHIFT(7 : 0)
+ },
+ {
+ ID(VI_WY),
+ VI_TL_RA(4), MASK(15 : 8), SHIFT(15 : 8),
+ VI_TM_RA(0), MASK(31 : 24), SHIFT(31 : 24),
+ VI_TH_RA(VIWY), MASK(7 : 0), SHIFT(7 : 0)
+ }
+};
+
+static int ns_per_tick = 30;
+/* Tegra3 MC atom size in bytes */
+static const int normal_atom_size = 16;
+#endif
+
+#endif /* _MACH_TEGRA_TEGRA3_LA_PRIV_H_ */
diff --git a/arch/arm/mach-tegra/tegra3_speedo.c b/arch/arm/mach-tegra/tegra3_speedo.c
index 78afb2804088..2889f656f47a 100644
--- a/arch/arm/mach-tegra/tegra3_speedo.c
+++ b/arch/arm/mach-tegra/tegra3_speedo.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_speedo.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
@@ -23,6 +23,8 @@
#include <linux/err.h>
#include <mach/iomap.h>
#include <mach/tegra_fuse.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
#include "fuse.h"
@@ -128,6 +130,11 @@ static int core_process_id;
static int cpu_speedo_id;
static int soc_speedo_id;
static int package_id;
+/*
+ * Only AP37 supports App Profile
+ * This informs user space of support without exposing cpu id's
+ */
+static int enable_app_profiles;
static void fuse_speedo_calib(u32 *speedo_g, u32 *speedo_lp)
{
@@ -267,6 +274,7 @@ static void rev_sku_to_speedo_ids(int rev, int sku)
cpu_speedo_id = 12;
soc_speedo_id = 2;
threshold_index = 9;
+ enable_app_profiles = 1;
break;
default:
pr_err("Tegra3 Rev-A02: Reserved pkg: %d\n",
@@ -560,3 +568,15 @@ int tegra_core_speedo_mv(void)
BUG();
}
}
+
+static int get_enable_app_profiles(char *val, const struct kernel_param *kp)
+{
+ return param_get_uint(val, kp);
+}
+
+static struct kernel_param_ops tegra_profiles_ops = {
+ .get = get_enable_app_profiles,
+};
+
+module_param_cb(tegra_enable_app_profiles,
+ &tegra_profiles_ops, &enable_app_profiles, 0444);
diff --git a/arch/arm/mach-tegra/tegra3_thermal.c b/arch/arm/mach-tegra/tegra3_thermal.c
index f36f84ccddf4..9de34a05810c 100644
--- a/arch/arm/mach-tegra/tegra3_thermal.c
+++ b/arch/arm/mach-tegra/tegra3_thermal.c
@@ -281,9 +281,9 @@ static void tegra_thermal_alert_unlocked(void *data)
#ifdef CONFIG_TEGRA_EDP_LIMITS
/* inform edp governor */
if (edp_thermal_zone_val != temp_tj) {
- long temp_edp = (dev2tj(device, temp_tj) - therm->edp_offset) / 1000;
+ long temp_edp = (temp_tj - therm->edp_offset) / 1000;
tegra_edp_update_thermal_zone(temp_edp);
- edp_thermal_zone_val = temp_edp;
+ edp_thermal_zone_val = temp_tj;
}
#endif
}
@@ -441,7 +441,6 @@ int tegra_thermal_device_register(struct tegra_thermal_device *device)
tegra_skin_device_register(device);
#endif
- register_pm_notifier(&tegra_thermal_nb);
return 0;
}
@@ -477,6 +476,8 @@ int __init tegra_thermal_init(struct tegra_thermal_data *data,
throttle_list = tlist;
throttle_list_size = tlist_size;
+ register_pm_notifier(&tegra_thermal_nb);
+
return 0;
}
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c
index 3a831c59a750..66637f29b19c 100644
--- a/arch/arm/mach-tegra/tegra3_usb_phy.c
+++ b/arch/arm/mach-tegra/tegra3_usb_phy.c
@@ -473,6 +473,11 @@
#define PHY_DBG(stuff...) do {} while (0)
#endif
+/* define HSIC phy params */
+#define HSIC_SYNC_START_DELAY 9
+#define HSIC_IDLE_WAIT_DELAY 17
+#define HSIC_ELASTIC_UNDERRUN_LIMIT 16
+#define HSIC_ELASTIC_OVERRUN_LIMIT 16
static u32 utmip_rctrl_val, utmip_tctrl_val;
static DEFINE_SPINLOCK(utmip_pad_lock);
@@ -632,12 +637,6 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
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);
@@ -721,10 +720,6 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
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);
@@ -744,6 +739,11 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
writel(val, pmc_base + PMC_USB_AO);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WALK_PTR(inst);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
phy->remote_wakeup = false;
PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
}
@@ -766,8 +766,7 @@ bool utmi_phy_remotewake_detected(struct tegra_usb_phy *phy)
writel(val, pmc_base + PMC_SLEEP_CFG);
val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CLR_WAKE_ALARM(inst) |
- UTMIP_CLR_WALK_PTR(inst);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
writel(val, pmc_base + PMC_TRIGGERS);
val = readl(base + UTMIP_PMC_WAKEUP0);
@@ -989,7 +988,8 @@ static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
/* 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)
+ if ((phy->port_speed == USB_PHY_PORT_SPEED_HIGH) ||
+ (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC))
val |= USB_PORTSC_PTC(5);
else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
val |= USB_PORTSC_PTC(6);
@@ -1222,19 +1222,23 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy)
{
void __iomem *base = phy->regs;
unsigned long val = 0;
+ bool remote_wakeup = false;
+ int irq_status = IRQ_HANDLED;
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));
+ 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));
+ 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))
+ if (utmi_phy_remotewake_detected(phy)) {
pr_info("%s: utmip remote wake detected\n", __func__);
+ remote_wakeup = true;
+ }
if (phy->pdata->u_data.host.hot_plug) {
val = readl(base + USB_SUSP_CTRL);
@@ -1242,19 +1246,36 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy)
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));
+
+ /* In case of remote wakeup PHY clock will not up
+ immediately, so should not access any controller
+ register but normal plug-in/plug-out should be
+ executed */
+ if (!remote_wakeup) {
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI)) {
+ irq_status = IRQ_NONE;
+ goto exit;
+ }
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val &= ~USB_PORTSC_WKCN;
+ else
+ val &= ~USB_PORTSC_WKDS;
+ val &= ~USB_PORTSC_RWC_BITS;
+ writel(val , (base + USB_PORTSC));
+ }
} else if (!phy->phy_clk_on) {
- return IRQ_NONE;
+ if (remote_wakeup)
+ irq_status = IRQ_HANDLED;
+ else
+ irq_status = IRQ_NONE;
+ goto exit;
}
}
-
- return IRQ_HANDLED;
+exit:
+ return irq_status;
}
static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy)
@@ -1466,8 +1487,12 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
enable_hotplug = (val & USB_ID_STATUS) ? false : true;
}
if (enable_hotplug) {
+ /* Enable wakeup event of device plug-in/plug-out */
val = readl(base + USB_PORTSC);
- val |= USB_PORTSC_WKCN;
+ if (val & USB_PORTSC_CCS)
+ val |= USB_PORTSC_WKDS;
+ else
+ val |= USB_PORTSC_WKCN;
writel(val, base + USB_PORTSC);
val = readl(base + USB_SUSP_CTRL);
@@ -1481,6 +1506,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
}
}
+ /* Disable PHY clock */
val = readl(base + HOSTPC1_DEVLC);
val |= HOSTPC1_DEVLC_PHCD;
writel(val, base + HOSTPC1_DEVLC);
@@ -1647,11 +1673,11 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
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);
- }
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst))
+ utmip_phy_disable_pmc_bus_ctrl(phy);
}
+
utmi_phy_enable_obs_bus(phy);
}
@@ -1669,7 +1695,9 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
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);
+ PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout"
+ "val = 0x%lx instance = %d\n",
+ __func__, val, phy->inst);
utmip_phy_disable_pmc_bus_ctrl(phy);
utmi_phy_post_resume(phy);
return;
@@ -1810,6 +1838,31 @@ static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
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);
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* turn off 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);
+
+ /* 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 &= ~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_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
{
unsigned long val;
@@ -1844,6 +1897,30 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
val |= UHSIC_PWR;
writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~UHSIC_STROBE_VAL;
+ val &= ~UHSIC_DATA_VAL;
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Clear walk enable */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val &= ~UHSIC_LINEVAL_WALK_EN;
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* 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);
/* Enable which type of event can trigger a walk,
* in this case usb_line_wake */
@@ -1860,19 +1937,16 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
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;
@@ -1880,19 +1954,21 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
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*/
+ /* Setting Wake event*/
val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UHSIC_WAKE_VAL(~0);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
val |= UHSIC_WAKE_VAL(WAKE_VAL_SD10);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* Clear the walk pointers and wake alarm */
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
val |= UHSIC_MASTER_ENABLE;
writel(val, pmc_base + PMC_SLEEP_CFG);
@@ -1911,14 +1987,10 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
DBG("%s (%d)\n", __func__, __LINE__);
val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UHSIC_WAKE_VAL(0x0);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
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);
@@ -1933,6 +2005,10 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
val |= (STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
writel(val, pmc_base + PMC_USB_AO);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= (UHSIC_CLR_WALK_PTR_P0 | UHSIC_CLR_WAKE_ALARM_P0);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
phy->remote_wakeup = false;
}
@@ -1947,12 +2023,12 @@ static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
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_ANY);
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;
+ val |= UHSIC_CLR_WAKE_ALARM_P0;
writel(val, pmc_base + PMC_TRIGGERS);
val = readl(base + UHSIC_PMC_WAKEUP0);
@@ -2003,14 +2079,10 @@ static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
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);
- }
+ 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);
}
}
@@ -2019,7 +2091,7 @@ 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 */
+ int wait_time_us = 25000; /* FPR should be set by this time */
DBG("%s(%d)\n", __func__, __LINE__);
@@ -2035,9 +2107,8 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
return;
}
wait_time_us--;
- } while (!(val & USB_PORTSC_RESUME));
- /* wait for 25 ms to port resume complete */
- msleep(25);
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+
/* disable PMC master control */
uhsic_phy_disable_pmc_bus_ctrl(phy);
@@ -2050,25 +2121,73 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
pr_warn("%s: timeout waiting for SOF\n", __func__);
}
uhsic_phy_post_resume(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;
+ }
} 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 hsic_rail_enable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ phy->hsic_reg = regulator_get(NULL, "avdd_hsic");
+ if (IS_ERR_OR_NULL(phy->hsic_reg)) {
+ pr_err("HSIC: Could not get regulator avdd_hsic\n");
+ phy->hsic_reg = NULL;
+ return PTR_ERR(phy->hsic_reg);
+ }
}
+
+ ret = regulator_enable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("%s avdd_hsic could not be enabled\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hsic_rail_disable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ pr_warn("%s: unbalanced disable\n", __func__);
+ return -EIO;
+ }
+
+ ret = regulator_disable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("HSIC regulator avdd_hsic cannot be disabled\n");
+ return ret;
+ }
+
+ return 0;
}
static int uhsic_phy_open(struct tegra_usb_phy *phy)
{
unsigned long parent_rate;
int i;
+ int ret;
+
+ phy->hsic_reg = NULL;
+ ret = hsic_rail_enable(phy);
+ if (ret < 0) {
+ pr_err("%s avdd_hsic could not be enabled\n", __func__);
+ return ret;
+ }
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
@@ -2088,6 +2207,18 @@ static int uhsic_phy_open(struct tegra_usb_phy *phy)
return 0;
}
+static void uhsic_phy_close(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ uhsic_powerdown_pmc_wake_detect(phy);
+
+ ret = hsic_rail_disable(phy);
+ if (ret < 0)
+ pr_err("%s avdd_hsic could not be disabled\n", __func__);
+}
+
static int uhsic_phy_irq(struct tegra_usb_phy *phy)
{
usb_phy_fence_read(phy);
@@ -2101,7 +2232,6 @@ 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);
@@ -2127,13 +2257,13 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
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);
+ val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_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);
+ val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY);
writel(val, base + UHSIC_HSRX_CFG1);
/* WAR HSIC TX */
@@ -2173,8 +2303,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
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);
@@ -2203,6 +2331,15 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
phy->phy_clk_on = true;
phy->hw_accessible = true;
+ if (phy->pmc_sleepwalk) {
+ DBG("%s(%d) inst:[%d] restore phy\n", __func__, __LINE__,
+ phy->inst);
+ uhsic_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ uhsic_phy_restore_end(phy);
+ phy->pmc_sleepwalk = false;
+ }
+
return 0;
}
@@ -2224,12 +2361,20 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
/* Disable interrupts */
writel(0, base + USB_USBINTR);
- uhsic_setup_pmc_wake_detect(phy);
+ if (phy->pmc_sleepwalk == false) {
+ uhsic_setup_pmc_wake_detect(phy);
+ phy->pmc_sleepwalk = true;
+ }
val = readl(base + HOSTPC1_DEVLC);
val |= HOSTPC1_DEVLC_PHCD;
writel(val, base + HOSTPC1_DEVLC);
+ /* Remove power downs for HSIC from PADS CFG1 register */
+ val = readl(base + UHSIC_PADS_CFG1);
+ val |= (UHSIC_PD_BG |UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
phy->phy_clk_on = false;
phy->hw_accessible = false;
@@ -2251,8 +2396,6 @@ int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
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);
@@ -2292,8 +2435,6 @@ static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
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 */
@@ -2373,10 +2514,6 @@ 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;
}
@@ -2528,6 +2665,9 @@ static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
{
+ unsigned int val;
+ void __iomem *base = phy->regs;
+
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
if (!phy->phy_clk_on) {
@@ -2539,6 +2679,9 @@ static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
phy->phy_clk_on = false;
phy->hw_accessible = false;
ulpi_null_phy_set_tristate(true);
+ val = readl(base + ULPIS2S_CTRL);
+ val &= ~ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
return 0;
}
@@ -2563,7 +2706,16 @@ static int ulpi_null_phy_init(struct tegra_usb_phy *phy)
static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
usb_phy_fence_read(phy);
+ if (phy->bus_reseting){
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ phy->bus_reseting = false;
+ }
return IRQ_HANDLED;
}
@@ -2589,6 +2741,23 @@ static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy)
return 0;
}
+static int ulpi_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);
+
+ /*DISABLE RUN BIT */
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ phy->bus_reseting = true;
+
+ return 0;
+}
+
static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
{
struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
@@ -2761,6 +2930,7 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
}
udelay(10);
+ phy->bus_reseting = false;
phy->phy_clk_on = true;
phy->hw_accessible = true;
@@ -2823,6 +2993,7 @@ static struct tegra_usb_phy_ops utmi_phy_ops = {
static struct tegra_usb_phy_ops uhsic_phy_ops = {
.open = uhsic_phy_open,
+ .close = uhsic_phy_close,
.irq = uhsic_phy_irq,
.power_on = uhsic_phy_power_on,
.power_off = uhsic_phy_power_off,
@@ -2844,6 +3015,7 @@ static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
.resume = ulpi_null_phy_resume,
.post_resume = ulpi_null_phy_post_resume,
.reset = ulpi_null_phy_cmd_reset,
+ .bus_reset = ulpi_phy_bus_reset,
};
static struct tegra_usb_phy_ops ulpi_link_phy_ops;
diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/tegra_fuse.c
index 6df9da994fb9..11328c4cada3 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/tegra_fuse.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/fuse.c
+ * arch/arm/mach-tegra/tegra_fuse.c
*
* Copyright (C) 2010 Google, Inc.
* Copyright (C) 2010-2012 NVIDIA Corp.
@@ -62,6 +62,21 @@
#endif
+#define TEGRA_AGE_0_6 0x2cc /*Spare bit 34*/
+#define TEGRA_AGE_1_6 0x308 /*Spare bit 49*/
+#define TEGRA_AGE_0_5 0x2c8 /*Spare bit 33*/
+#define TEGRA_AGE_1_5 0x304 /*Spare bit 48*/
+#define TEGRA_AGE_0_4 0x2c4 /*Spare bit 32*/
+#define TEGRA_AGE_1_4 0x300 /*Spare bit 47*/
+#define TEGRA_AGE_0_3 0x2c0 /*Spare bit 31*/
+#define TEGRA_AGE_1_3 0x2fc /*Spare bit 46*/
+#define TEGRA_AGE_0_2 0x2bc /*Spare bit 30*/
+#define TEGRA_AGE_1_2 0x2f8 /*Spare bit 45*/
+#define TEGRA_AGE_0_1 0x2b8 /*Spare bit 29*/
+#define TEGRA_AGE_1_1 0x2f4 /*Spare bit 44*/
+#define TEGRA_AGE_0_0 0x2b4 /*Spare bit 28*/
+#define TEGRA_AGE_1_0 0x2f0 /*Spare bit 43*/
+
struct tegra_id {
enum tegra_chipid chipid;
unsigned int major, minor, netlist, patch;
@@ -172,6 +187,35 @@ int tegra_fuse_get_tsensor_spare_bits(u32 *spare_bits)
EXPORT_SYMBOL(tegra_fuse_get_tsensor_spare_bits);
#endif
+#define TEGRA_READ_AGE_BIT(n, bit, age) {\
+ bit = tegra_fuse_readl(TEGRA_AGE_0_##n);\
+ bit |= tegra_fuse_readl(TEGRA_AGE_1_##n);\
+ bit = bit << n;\
+ age |= bit;\
+}
+
+int tegra_get_age(void)
+{
+ int linear_age, age_bit;
+ linear_age = age_bit = 0;
+
+ TEGRA_READ_AGE_BIT(6, age_bit, linear_age);
+ TEGRA_READ_AGE_BIT(5, age_bit, linear_age);
+ TEGRA_READ_AGE_BIT(4, age_bit, linear_age);
+ TEGRA_READ_AGE_BIT(3, age_bit, linear_age);
+ TEGRA_READ_AGE_BIT(2, age_bit, linear_age);
+ TEGRA_READ_AGE_BIT(1, age_bit, linear_age);
+ TEGRA_READ_AGE_BIT(0, age_bit, linear_age);
+
+ /*Default Aug, 2012*/
+ if (linear_age <= 0)
+ linear_age = 8;
+
+ pr_info("TEGRA: Linear age: %d\n", linear_age);
+
+ return linear_age;
+}
+
unsigned long long tegra_chip_uid(void)
{
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
diff --git a/arch/arm/mach-tegra/tegra_odm_fuses.c b/arch/arm/mach-tegra/tegra_odm_fuses.c
index 06b831c31967..ae82ed56f0f0 100644
--- a/arch/arm/mach-tegra/tegra_odm_fuses.c
+++ b/arch/arm/mach-tegra/tegra_odm_fuses.c
@@ -53,6 +53,7 @@
#define NFUSES 64
#define STATE_IDLE (0x4 << 16)
+#define SENSE_DONE (0x1 << 30)
/* since fuse burning is irreversible, use this for testing */
#define ENABLE_FUSE_BURNING 1
@@ -607,6 +608,17 @@ static void fuse_program_array(int pgm_cycles)
}
fuse_power_disable();
+
+ /*
+ * Wait until done (polling)
+ * this one needs to use fuse_sense done, the FSM follows a periodic
+ * sequence that includes idle
+ */
+ do {
+ udelay(1);
+ reg = tegra_fuse_readl(FUSE_CTRL);
+ } while ((reg & (0x1 << 30)) != SENSE_DONE);
+
}
static int fuse_set(enum fuse_io_param io_param, u32 *param, int size)
diff --git a/arch/arm/mach-tegra/tegra_usb_modem_power.c b/arch/arm/mach-tegra/tegra_usb_modem_power.c
index bb9495a329a6..8e93a7cdca97 100644
--- a/arch/arm/mach-tegra/tegra_usb_modem_power.c
+++ b/arch/arm/mach-tegra/tegra_usb_modem_power.c
@@ -307,8 +307,6 @@ static int mdm_request_wakeable_irq(struct tegra_usb_modem *modem,
if (ret)
return ret;
- tegra_gpio_enable(irq_gpio);
-
/* enable IRQ for GPIO */
*irq = gpio_to_irq(irq_gpio);
@@ -400,7 +398,8 @@ static ssize_t load_unload_usb_host(struct device *dev,
return count;
}
-static DEVICE_ATTR(load_host, 0666, show_usb_host, load_unload_usb_host);
+static DEVICE_ATTR(load_host, S_IRUSR | S_IWUSR, show_usb_host,
+ load_unload_usb_host);
static int mdm_init(struct tegra_usb_modem *modem, struct platform_device *pdev)
{
diff --git a/arch/arm/mach-tegra/tegra_usb_phy.h b/arch/arm/mach-tegra/tegra_usb_phy.h
index 0dc4cd73c5e7..05aa88296619 100644
--- a/arch/arm/mach-tegra/tegra_usb_phy.h
+++ b/arch/arm/mach-tegra/tegra_usb_phy.h
@@ -80,6 +80,7 @@ struct tegra_usb_phy {
struct clk *emc_clk;
struct clk *sys_clk;
struct regulator *vdd_reg;
+ struct regulator *hsic_reg;
struct regulator *vbus_reg;
struct tegra_usb_phy_ops *ops;
struct tegra_xtal_freq *freq;
@@ -95,6 +96,9 @@ struct tegra_usb_phy {
bool remote_wakeup;
bool hw_accessible;
bool ulpi_clk_padout_ena;
+ bool pmc_sleepwalk;
+ bool bus_reseting;
+ bool linkphy_init;
};
int usb_phy_reg_status_wait(void __iomem *reg, u32 mask,
diff --git a/arch/arm/mach-tegra/timer-t3.c b/arch/arm/mach-tegra/timer-t3.c
index f23873b214b2..b58fc9bbc4c0 100644
--- a/arch/arm/mach-tegra/timer-t3.c
+++ b/arch/arm/mach-tegra/timer-t3.c
@@ -72,10 +72,8 @@ static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE);
#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/timer.c b/arch/arm/mach-tegra/timer.c
index 83d0e17b50c1..5771bfc9bdde 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -31,6 +31,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>
+#include <linux/rtc.h>
#include <asm/mach/time.h>
#include <asm/localtimer.h>
@@ -238,6 +239,96 @@ void tegra_twd_resume(struct tegra_twd_context *context)
}
#endif
+#ifdef CONFIG_RTC_CLASS
+/**
+ * has_readtime - check rtc device has readtime ability
+ * @dev: current device
+ * @name_ptr: name to be returned
+ *
+ * This helper function checks to see if the rtc device can be
+ * used for reading time
+ */
+static int has_readtime(struct device *dev, void *name_ptr)
+{
+ struct rtc_device *candidate = to_rtc_device(dev);
+
+ if (!candidate->ops->read_time)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * tegra_get_linear_age - helper function to return linear age
+ * from Jan 2012.
+ *
+ * @return
+ * 1 - Jan 2012,
+ * 2 - Feb 2012,
+ * .....
+ * 13 - Jan 2013
+ */
+int tegra_get_linear_age(void)
+{
+ struct rtc_time tm;
+ int year, month, linear_age;
+ struct rtc_device *rtc_dev = NULL;
+ const char *name = NULL;
+ int ret;
+ struct device *dev = NULL;
+
+ linear_age = -1;
+ year = month = 0;
+ dev = class_find_device(rtc_class, NULL, &name, has_readtime);
+
+ if (!dev) {
+ pr_err("DVFS: No device with readtime capability\n");
+ goto done;
+ }
+
+ name = dev_name(dev);
+
+ pr_info("DVFS: Got RTC device name:%s\n", name);
+
+ if (name)
+ rtc_dev = rtc_class_open((char *)name);
+
+ if (!rtc_dev) {
+ pr_err("DVFS: No RTC device\n");
+ goto error_dev;
+ }
+
+ ret = rtc_read_time(rtc_dev, &tm);
+
+ if (ret < 0) {
+ pr_err("DVFS: Can't read RTC time\n");
+ goto error_rtc;
+ }
+
+ year = tm.tm_year;
+ /*Normalize it to 2012*/
+ year -= 112;
+ month = tm.tm_mon + 1;
+
+ if (year >= 0)
+ linear_age = year * 12 + month;
+
+error_rtc:
+ rtc_class_close(rtc_dev);
+error_dev:
+ put_device(dev);
+done:
+ return linear_age;
+
+}
+
+#else
+int tegra_get_linear_age()
+{
+ return -1;
+}
+#endif
+
static void __init tegra_init_timer(void)
{
struct clk *clk;
diff --git a/arch/arm/mach-tegra/timer.h b/arch/arm/mach-tegra/timer.h
index 4a91792f5d99..47628330dceb 100644
--- a/arch/arm/mach-tegra/timer.h
+++ b/arch/arm/mach-tegra/timer.h
@@ -45,11 +45,14 @@ struct tegra_twd_context {
int tegra_twd_get_state(struct tegra_twd_context *context);
void tegra_twd_suspend(struct tegra_twd_context *context);
void tegra_twd_resume(struct tegra_twd_context *context);
+int tegra_get_linear_age(void);
#else
static inline int tegra_twd_get_state(struct tegra_twd_context *context)
{ return -ENODEV; }
static inline void tegra_twd_suspend(struct tegra_twd_context *context) {}
static inline void tegra_twd_resume(struct tegra_twd_context *context) {}
+static inline int tegra_get_linear_age()
+{ return -1; }
#endif
#endif /* _MACH_TEGRA_TIMER_H_ */
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 654976b7b1c1..b5d3dc575e0c 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -137,7 +137,7 @@ static irqreturn_t usb_phy_dev_vbus_pmu_irq_thr(int irq, void *pdata)
if (phy->vdd_reg && !phy->vdd_reg_on) {
regulator_enable(phy->vdd_reg);
- phy->vdd_reg_on = 1;
+ phy->vdd_reg_on = true;
/*
* Optimal time to get the regulator turned on
* before detecting vbus interrupt.
@@ -224,7 +224,6 @@ fail_ctrlr_clk:
clk_put(phy->pllu_clk);
fail_pll:
-
return err;
}
@@ -234,29 +233,34 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
struct tegra_usb_platform_data *pdata;
struct resource *res;
int err;
+ int plat_data_size = sizeof(struct tegra_usb_platform_data);
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);
+ err = -EINVAL;
+ goto fail_inval;
}
- phy = kzalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
+ phy = devm_kzalloc(&pdev->dev, sizeof(struct tegra_usb_phy), GFP_KERNEL);
if (!phy) {
ERR("inst:[%d] malloc usb phy failed\n", pdev->id);
- return ERR_PTR(-ENOMEM);
+ err = -ENOMEM;
+ goto fail_nomem;
}
- phy->pdata = kzalloc(sizeof(struct tegra_usb_platform_data), GFP_KERNEL);
+ phy->pdata = devm_kzalloc(&pdev->dev, plat_data_size, GFP_KERNEL);
if (!phy->pdata) {
ERR("inst:[%d] malloc usb phy pdata failed\n", pdev->id);
- kfree(phy);
- return ERR_PTR(-ENOMEM);
+ devm_kfree(&pdev->dev, phy);
+ err = -ENOMEM;
+ goto fail_nomem;
}
- memcpy(phy->pdata, pdata, sizeof(struct tegra_usb_platform_data));
+ memcpy(phy->pdata, pdata, plat_data_size);
+
phy->pdev = pdev;
phy->inst = pdev->id;
@@ -276,7 +280,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
goto fail_io;
}
- phy->vdd_reg = regulator_get(NULL, "avdd_usb");
+ phy->vdd_reg = regulator_get(&pdev->dev, "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));
@@ -312,6 +316,7 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
instance : %d\n", PTR_ERR(phy->vbus_reg),
phy->inst);
err = PTR_ERR(phy->vbus_reg);
+ phy->vbus_reg = NULL;
goto fail_init;
}
} else {
@@ -322,8 +327,6 @@ struct tegra_usb_phy *tegra_usb_phy_open(struct platform_device *pdev)
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);
@@ -377,8 +380,11 @@ fail_clk:
regulator_put(phy->vdd_reg);
iounmap(phy->regs);
fail_io:
- kfree(phy);
+ devm_kfree(&pdev->dev, phy->pdata);
+ devm_kfree(&pdev->dev, phy);
+fail_nomem:
+fail_inval:
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_open);
@@ -418,11 +424,10 @@ void tegra_usb_phy_close(struct tegra_usb_phy *phy)
regulator_put(phy->vdd_reg);
}
-
tegra_usb_phy_release_clocks(phy);
- kfree(phy->pdata);
- kfree(phy);
+ devm_kfree(&phy->pdev->dev, phy->pdata);
+ devm_kfree(&phy->pdev->dev, phy);
}
EXPORT_SYMBOL_GPL(tegra_usb_phy_close);
@@ -435,6 +440,7 @@ irqreturn_t tegra_usb_phy_irq(struct tegra_usb_phy *phy)
return status;
}
+
int tegra_usb_phy_init(struct tegra_usb_phy *phy)
{
int status = 0;
@@ -472,25 +478,30 @@ int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
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)
+ !phy->pdata->u_data.host.remote_wakeup_supported) {
clk_disable(phy->ctrlr_clk);
+ phy->ctrl_clk_on = false;
+ if (phy->vdd_reg && phy->vdd_reg_on) {
+ regulator_disable(phy->vdd_reg);
+ phy->vdd_reg_on = false;
+ }
+ }
} 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
+ /* In device mode clock regulator/clocks will be turned off
+ * only if pmu interrupt is present on the board and host mode
+ * support through OTG is supported on the board.
*/
- if (phy->pdata->u_data.dev.vbus_pmu_irq) {
+ if (phy->pdata->u_data.dev.vbus_pmu_irq &&
+ phy->pdata->builtin_host_disabled) {
clk_disable(phy->ctrlr_clk);
phy->ctrl_clk_on = false;
+ if (phy->vdd_reg && phy->vdd_reg_on) {
+ regulator_disable(phy->vdd_reg);
+ phy->vdd_reg_on = false;
+ }
}
}
- 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;
- }
-
phy->phy_power_on = false;
return err;
@@ -552,6 +563,7 @@ int tegra_usb_phy_reset(struct tegra_usb_phy *phy)
return status;
}
+
int tegra_usb_phy_pre_suspend(struct tegra_usb_phy *phy)
{
int status = 0;
@@ -566,6 +578,7 @@ int tegra_usb_phy_pre_suspend(struct tegra_usb_phy *phy)
return status;
}
+
int tegra_usb_phy_suspend(struct tegra_usb_phy *phy)
{
int err = 0;
@@ -581,6 +594,7 @@ int tegra_usb_phy_suspend(struct tegra_usb_phy *phy)
return err;
}
+
int tegra_usb_phy_post_suspend(struct tegra_usb_phy *phy)
{
int status = 0;
@@ -595,6 +609,7 @@ int tegra_usb_phy_post_suspend(struct tegra_usb_phy *phy)
return status;
}
+
int tegra_usb_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
{
int status = 0;
@@ -609,6 +624,7 @@ int tegra_usb_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
return status;
}
+
int tegra_usb_phy_resume(struct tegra_usb_phy *phy)
{
int err = 0;
@@ -625,6 +641,7 @@ int tegra_usb_phy_resume(struct tegra_usb_phy *phy)
return err;
}
+
int tegra_usb_phy_post_resume(struct tegra_usb_phy *phy)
{
int status = 0;
@@ -639,6 +656,7 @@ int tegra_usb_phy_post_resume(struct tegra_usb_phy *phy)
return status;
}
+
int tegra_usb_phy_port_power(struct tegra_usb_phy *phy)
{
int status = 0;
@@ -650,6 +668,7 @@ int tegra_usb_phy_port_power(struct tegra_usb_phy *phy)
return status;
}
+
int tegra_usb_phy_bus_reset(struct tegra_usb_phy *phy)
{
int status = 0;
diff --git a/arch/arm/mach-tegra/wakeups-t2.h b/arch/arm/mach-tegra/wakeups-t2.h
index 955b351a71fa..142d4c76558b 100644
--- a/arch/arm/mach-tegra/wakeups-t2.h
+++ b/arch/arm/mach-tegra/wakeups-t2.h
@@ -27,9 +27,6 @@
#error "Tegra 2 wakeup sources valid only for CONFIG_ARCH_TEGRA_2x_SOC"
#endif
-int tegra_irq_to_wake(int irq);
-int tegra_wake_to_irq(int wake);
-
#define TEGRA_WAKE_GPIO_PO5 0
#define TEGRA_WAKE_GPIO_PV3 1
#define TEGRA_WAKE_GPIO_PL1 2
diff --git a/arch/arm/mach-tegra/wakeups-t3.c b/arch/arm/mach-tegra/wakeups-t3.c
index ef471cb035db..dd042f8fafc0 100644
--- a/arch/arm/mach-tegra/wakeups-t3.c
+++ b/arch/arm/mach-tegra/wakeups-t3.c
@@ -66,7 +66,8 @@ static struct tegra_wake_info tegra_wake_event_data_t3[] = {
{-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_USB3, POLARITY_LEVEL_HI}, /* TEGRA_USB3_UTMIP, */ /* wake41 */
+ {INT_USB2, POLARITY_LEVEL_HI}, /* TEGRA_USB2_UHSIC, */ /* wake42 */
};
struct tegra_wake_info *tegra_wake_event_data = tegra_wake_event_data_t3;
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index e6871a3e4d1c..972c7bd08a83 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -83,7 +83,8 @@ static inline void l2x0_inv_line(unsigned long addr)
writel_relaxed(addr, base + L2X0_INV_LINE_PA);
}
-#if defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915)
+#if !defined(CONFIG_TRUSTED_FOUNDATIONS) && \
+ (defined(CONFIG_PL310_ERRATA_588369) || defined(CONFIG_PL310_ERRATA_727915))
#define debug_writel(val) outer_cache.set_debug(val)
@@ -161,7 +162,7 @@ static void l2x0_flush_all(void)
unsigned long flags;
#ifdef CONFIG_PL310_ERRATA_727915
- if (is_pl310_rev(REV_PL310_R2P0)) {
+ if (is_pl310_rev(REV_PL310_R2P0) || is_pl310_rev(REV_PL310_R3P1_50)) {
l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_INV_LINE_IDX);
return;
}
@@ -178,7 +179,7 @@ static void l2x0_clean_all(void)
unsigned long flags;
#ifdef CONFIG_PL310_ERRATA_727915
- if (is_pl310_rev(REV_PL310_R2P0)) {
+ if (is_pl310_rev(REV_PL310_R2P0) || is_pl310_rev(REV_PL310_R3P1_50)) {
l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_LINE_IDX);
return;
}
@@ -418,6 +419,7 @@ void l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
outer_cache.flush_range = l2x0_flush_range;
outer_cache.sync = l2x0_cache_sync;
outer_cache.flush_all = l2x0_flush_all;
+ outer_cache.clean_all = l2x0_clean_all;
outer_cache.inv_all = l2x0_inv_all;
outer_cache.disable = l2x0_disable;
outer_cache.set_debug = l2x0_set_debug;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 6f81c8e05c3a..cb4e96e1019d 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -339,7 +339,7 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
#ifdef CONFIG_XIP_KERNEL
memblock_reserve(__pa(_sdata), _end - _sdata);
#else
- memblock_reserve(__pa(_stext), _end - _stext);
+ memblock_reserve(__pa(_stext), ALIGN(_end - _stext, PMD_SIZE));
#endif
#ifdef CONFIG_BLK_DEV_INITRD
if (phys_initrd_size &&
@@ -734,6 +734,7 @@ void __init mem_init(void)
void free_initmem(void)
{
+#ifndef CONFIG_CPA
#ifdef CONFIG_HAVE_TCM
extern char __tcm_start, __tcm_end;
@@ -748,6 +749,7 @@ void free_initmem(void)
totalram_pages += free_area(__phys_to_pfn(__pa(__init_begin)),
__phys_to_pfn(__pa(__init_end)),
"init");
+#endif
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -756,12 +758,14 @@ static int keep_initrd;
void free_initrd_mem(unsigned long start, unsigned long end)
{
+#ifndef CONFIG_CPA
if (!keep_initrd) {
poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
totalram_pages += free_area(__phys_to_pfn(__pa(start)),
__phys_to_pfn(__pa(end)),
"initrd");
}
+#endif
}
static int __init keepinitrd_setup(char *__unused)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index bb80555edac9..992bbc52938c 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -942,7 +942,7 @@ void __init arm_mm_memblock_reserve(void)
*/
memblock_reserve(__pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(pgd_t));
-#ifdef CONFIG_SA1111
+#if defined(CONFIG_SA1111) || defined(CONFIG_CPA)
/*
* Because of the SA1111 DMA bug, we want to preserve our
* precious DMA-able memory...
diff --git a/arch/arm/mm/pageattr.c b/arch/arm/mm/pageattr.c
index b7ff7f19b541..c11064517f56 100644
--- a/arch/arm/mm/pageattr.c
+++ b/arch/arm/mm/pageattr.c
@@ -39,6 +39,19 @@ static void inner_flush_cache_all(void)
}
#if defined(CONFIG_CPA)
+
+/*
+ * The arm kernel uses different cache policies(CPOLICY_WRITEBACK,
+ * CPOLICY_WRITEALLOC, CPOLICY_WRITETHROUGH) based on architecture version
+ * and smp mode. Using L_PTE_MT_WRITEALLOC or L_PTE_MT_WRITEBACK or
+ * L_PTE_MT_WRITETHROUGH directly in CPA code can result in restoring incorrect
+ * PTE attributes.
+ * pgprot_kernel would always have PTE attributes based on the cache policy
+ * in use for kernel cache memory. Use this to set the correct PTE attributes
+ * for kernel cache memory.
+ * */
+#define L_PTE_MT_KERNEL (pgprot_kernel & L_PTE_MT_MASK)
+
/*
* The current flushing context - we pass it instead of 5 arguments:
*/
@@ -224,7 +237,8 @@ static inline pgprot_t pte_to_pmd_pgprot(unsigned long pte,
{
pgprot_t ref_prot;
- ref_prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+ ref_prot = PMD_TYPE_SECT | PMD_DOMAIN(DOMAIN_KERNEL) |
+ PMD_SECT_AP_WRITE;
if (pte & L_PTE_MT_BUFFERABLE)
ref_prot |= PMD_SECT_BUFFERABLE;
@@ -232,17 +246,23 @@ static inline pgprot_t pte_to_pmd_pgprot(unsigned long pte,
if (pte & L_PTE_MT_WRITETHROUGH)
ref_prot |= PMD_SECT_CACHEABLE;
- if (pte & L_PTE_SHARED)
- ref_prot |= PMD_SECT_S;
-
if (pte & L_PTE_XN)
ref_prot |= PMD_SECT_XN;
+ if (pte & L_PTE_USER)
+ ref_prot |= PMD_SECT_AP_READ;
+
+ if (pte & (1 << 4))
+ ref_prot |= PMD_SECT_TEX(1);
+
if (pte & L_PTE_RDONLY)
- ref_prot &= ~PMD_SECT_AP_WRITE;
+ ref_prot |= PMD_SECT_APX;
+
+ if (pte & L_PTE_SHARED)
+ ref_prot |= PMD_SECT_S;
- ref_prot |= (ext_prot & (PTE_EXT_AP0 | PTE_EXT_AP1 | PTE_EXT_APX |
- PTE_EXT_NG | (7 << 6))) << 6;
+ if (pte & PTE_EXT_NG)
+ ref_prot |= PMD_SECT_nG;
return ref_prot;
}
@@ -250,9 +270,10 @@ static inline pgprot_t pte_to_pmd_pgprot(unsigned long pte,
static inline pgprot_t pmd_to_pte_pgprot(unsigned long pmd,
unsigned long *ext_prot)
{
- pgprot_t ref_prot = 0;
+ pgprot_t ref_prot;
- ref_prot |= L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_RDONLY;
+ *ext_prot = 0;
+ ref_prot = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
if (pmd & PMD_SECT_BUFFERABLE)
ref_prot |= L_PTE_MT_BUFFERABLE;
@@ -260,18 +281,23 @@ static inline pgprot_t pmd_to_pte_pgprot(unsigned long pmd,
if (pmd & PMD_SECT_CACHEABLE)
ref_prot |= L_PTE_MT_WRITETHROUGH;
- if (pmd & PMD_SECT_S)
- ref_prot |= L_PTE_SHARED;
-
if (pmd & PMD_SECT_XN)
ref_prot |= L_PTE_XN;
- if (pmd & PMD_SECT_AP_WRITE)
- ref_prot &= ~L_PTE_RDONLY;
+ if (pmd & PMD_SECT_AP_READ)
+ ref_prot |= L_PTE_USER;
+
+ if (pmd & PMD_SECT_TEX(1))
+ ref_prot |= (1 << 4);
- /* AP/APX/TEX bits */
- *ext_prot = (pmd & (PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
- PMD_SECT_APX | PMD_SECT_nG | (7 << 12))) >> 6;
+ if (pmd & PMD_SECT_APX)
+ ref_prot |= L_PTE_RDONLY;
+
+ if (pmd & PMD_SECT_S)
+ ref_prot |= L_PTE_SHARED;
+
+ if (pmd & PMD_SECT_nG)
+ ref_prot |= PTE_EXT_NG;
return ref_prot;
}
@@ -395,6 +421,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
if (numpages < cpa->numpages)
cpa->numpages = numpages;
+ old_pte = *kpte;
old_prot = new_prot = req_prot = pmd_to_pte_pgprot(pmd_val(*kpte),
&ext_prot);
@@ -476,6 +503,8 @@ static int split_large_page(pte_t *kpte, unsigned long address)
pgprot_t ref_prot = 0, ext_prot = 0;
int ret = 0;
+ BUG_ON((address & PMD_MASK) < __pa(_end));
+
pbase = pte_alloc_one_kernel(&init_mm, address);
if (!pbase)
return -ENOMEM;
@@ -502,6 +531,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
ref_prot = pmd_to_pte_pgprot(pmd_val(*kpte), &ext_prot);
+ BUG_ON(ref_prot != pgprot_kernel);
/*
* Get the target pfn from the original entry:
*/
@@ -760,7 +790,7 @@ static inline int cache_attr(pgprot_t attr)
* We need to flush the cache for all memory type changes
* except when a page is being marked write back cacheable
*/
- return !((pgprot_val(attr) & L_PTE_MT_MASK) == L_PTE_MT_WRITEBACK);
+ return !((pgprot_val(attr) & L_PTE_MT_MASK) == L_PTE_MT_KERNEL);
}
static int change_page_attr_set_clr(unsigned long *addr, int numpages,
@@ -916,7 +946,7 @@ EXPORT_SYMBOL(set_memory_wc);
int set_memory_wb(unsigned long addr, int numpages)
{
return change_page_attr_set_clr(&addr, numpages,
- __pgprot(L_PTE_MT_WRITEBACK),
+ __pgprot(L_PTE_MT_KERNEL),
__pgprot(L_PTE_MT_MASK),
0, 0, NULL);
}
@@ -934,7 +964,7 @@ EXPORT_SYMBOL(set_memory_iwb);
int set_memory_array_wb(unsigned long *addr, int addrinarray)
{
return change_page_attr_set_clr(addr, addrinarray,
- __pgprot(L_PTE_MT_WRITEBACK),
+ __pgprot(L_PTE_MT_KERNEL),
__pgprot(L_PTE_MT_MASK),
0, CPA_ARRAY, NULL);
@@ -1017,7 +1047,7 @@ EXPORT_SYMBOL(set_pages_array_wc);
int set_pages_array_wb(struct page **pages, int addrinarray)
{
return _set_pages_array(pages, addrinarray,
- L_PTE_MT_WRITEBACK, L_PTE_MT_MASK);
+ L_PTE_MT_KERNEL, L_PTE_MT_MASK);
}
EXPORT_SYMBOL(set_pages_array_wb);
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index e407a8501f53..8527c6df4548 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1116,5 +1116,7 @@ ubisys_p9d_evp MACH_UBISYS_P9D_EVP UBISYS_P9D_EVP 3493
atdgp318 MACH_ATDGP318 ATDGP318 3494
tegra_enterprise MACH_TEGRA_ENTERPRISE TEGRA_ENTERPRISE 3512
p1852 MACH_P1852 P1852 3651
-kai MACH_KAI KAI 3897
+kai MACH_KAI KAI 3897
p852 MACH_P852 P852 3667
+e1853 MACH_E1853 E1853 4241
+tai MACH_TAI TAI 4311
diff --git a/chromeos/config/armel/config.common.armel b/chromeos/config/armel/config.common.armel
index 98451e005db9..e2148214474f 100644
--- a/chromeos/config/armel/config.common.armel
+++ b/chromeos/config/armel/config.common.armel
@@ -158,8 +158,7 @@ CONFIG_CPU_V7=y
# 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_LL is not set
# CONFIG_DEBUG_USER is not set
# CONFIG_DEPRECATED_PARAM_STRUCT is not set
# CONFIG_DM9000 is not set
@@ -274,8 +273,10 @@ CONFIG_NEED_DMA_MAP_STATE=y
# CONFIG_NON_ALIASED_COHERENT_MEM is not set
CONFIG_NVMAP_ALLOW_SYSMEM=y
CONFIG_NVMAP_CACHE_MAINT_BY_SET_WAYS=y
+CONFIG_NVMAP_OUTER_CACHE_MAINT_BY_SET_WAYS=y
CONFIG_NVMAP_CARVEOUT_COMPACTOR=y
# CONFIG_NVMAP_CARVEOUT_KILLER is not set
+CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM=y
# CONFIG_NVMAP_HIGHMEM_ONLY is not set
CONFIG_NVMAP_PAGE_POOLS=y
CONFIG_NVMAP_PAGE_POOL_SIZE=0x0
@@ -455,20 +456,19 @@ CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_TEGRA_BB_XMM_POWER2 is not set
# CONFIG_TEGRA_BPC_MGMT is not set
CONFIG_TEGRA_CAMERA=y
+# CONFIG_TEGRA_CEC_SUPPORT is not set
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_DEBUG_UART_NONE=y
# 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_GADGET_BOOST_CPU_FREQ=0
CONFIG_TEGRA_GRHOST=y
CONFIG_TEGRA_GRHOST_DEFAULT_TIMEOUT=30000
CONFIG_TEGRA_GRHOST_USE_NVMAP=y
diff --git a/chromeos/config/armel/config.flavour.chromeos-tegra3 b/chromeos/config/armel/config.flavour.chromeos-tegra3
index 1b6f87579921..b2b52d044698 100644
--- a/chromeos/config/armel/config.flavour.chromeos-tegra3
+++ b/chromeos/config/armel/config.flavour.chromeos-tegra3
@@ -27,7 +27,7 @@ CONFIG_CRYPTO_CTS=y
CONFIG_DNOTIFY=y
CONFIG_DNS_RESOLVER=y
CONFIG_EXPORTFS=y
-# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_GIC_SET_MULTIPLE_CPUS=y
CONFIG_IPV6=y
CONFIG_IP_PNP=y
@@ -64,7 +64,6 @@ CONFIG_NFS_V3=y
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
@@ -97,8 +96,6 @@ 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
diff --git a/chromeos/config/armel/config.flavour.chromiumos-arm b/chromeos/config/armel/config.flavour.chromiumos-arm
index 3cfc11bfffc9..33c524d0d506 100644
--- a/chromeos/config/armel/config.flavour.chromiumos-arm
+++ b/chromeos/config/armel/config.flavour.chromiumos-arm
@@ -60,8 +60,6 @@ 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
diff --git a/chromeos/config/config.common.chromeos b/chromeos/config/config.common.chromeos
index 6c5db0fc665d..6d812040adca 100644
--- a/chromeos/config/config.common.chromeos
+++ b/chromeos/config/config.common.chromeos
@@ -291,8 +291,8 @@ CONFIG_CRYPTO_RNG2=y
# 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_SHA256=y
+CONFIG_CRYPTO_SHA512=m
# CONFIG_CRYPTO_TEA is not set
# CONFIG_CRYPTO_TEST is not set
# CONFIG_CRYPTO_TGR192 is not set
@@ -368,7 +368,7 @@ CONFIG_DEVTMPFS_MOUNT=y
# 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_CRYPT=y
# CONFIG_DM_DEBUG is not set
# CONFIG_DM_DELAY is not set
# CONFIG_DM_FLAKEY is not set
@@ -386,7 +386,6 @@ CONFIG_DUMMY_CONSOLE=y
# 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
@@ -969,6 +968,7 @@ CONFIG_MEDIA_TUNER_XC5000=m
# CONFIG_MFD_MAX8997 is not set
# CONFIG_MFD_MAX8998 is not set
# CONFIG_MFD_MC13XXX is not set
+# CONFIG_MFD_PALMAS is not set
# CONFIG_MFD_PCF50633 is not set
# CONFIG_MFD_RC5T583 is not set
# CONFIG_MFD_RDC321X is not set
@@ -1680,6 +1680,7 @@ CONFIG_TCP_MD5SIG=y
# CONFIG_TEST_POWER is not set
CONFIG_THERMAL=y
CONFIG_THERMAL_HWMON=y
+# CONFIG_THERM_EST is not set
CONFIG_TICK_ONESHOT=y
# CONFIG_TIFM_CORE is not set
CONFIG_TIMERFD=y
diff --git a/chromeos/config/i386/config.common.i386 b/chromeos/config/i386/config.common.i386
index a5a85733af59..f9d0c4998553 100644
--- a/chromeos/config/i386/config.common.i386
+++ b/chromeos/config/i386/config.common.i386
@@ -176,6 +176,7 @@ CONFIG_DRM_KMS_HELPER=y
CONFIG_E100=m
CONFIG_E1000=m
CONFIG_E1000E=m
+CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_DBGP=y
# CONFIG_EDAC is not set
# CONFIG_EDD is not set
diff --git a/chromeos/config/x86_64/config.common.x86_64 b/chromeos/config/x86_64/config.common.x86_64
index eab255dbd9e2..c65b0d3d8807 100644
--- a/chromeos/config/x86_64/config.common.x86_64
+++ b/chromeos/config/x86_64/config.common.x86_64
@@ -191,6 +191,7 @@ CONFIG_DRM_KMS_HELPER=y
CONFIG_E100=m
CONFIG_E1000=m
CONFIG_E1000E=m
+CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_DBGP=y
# CONFIG_EDAC is not set
# CONFIG_EDD is not set
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 4245ecf30f05..5e939d5f49e4 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
+CFLAGS_ahci-tegra.o = -Werror
obj-$(CONFIG_SATA_AHCI_TEGRA) += ahci-tegra.o libahci.o
obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 3f141ea9283d..37489733cb9d 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -406,8 +406,10 @@ static int rpm_suspend(struct device *dev, int rpmflags)
* reschedule another autosuspend.
*/
if ((rpmflags & RPM_AUTO) &&
- pm_runtime_autosuspend_expiration(dev) != 0)
+ pm_runtime_autosuspend_expiration(dev) != 0) {
+ wake_up_all(&dev->power.wait_queue);
goto repeat;
+ }
} else {
pm_runtime_cancel_pending(dev);
}
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 8eb56e273e75..2d3b713695c5 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_INTEL) += intel-agp.o
obj-$(CONFIG_AGP_INTEL) += intel-gtt.o
+CFLAGS_nvidia-agp.o = -Werror
obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o
obj-$(CONFIG_AGP_SIS) += sis-agp.o
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index baf4326e84c4..cf6ba6c1958e 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -30,8 +30,6 @@
#include <asm/cputime.h>
-static atomic_t active_count = ATOMIC_INIT(0);
-
struct cpufreq_interactive_cpuinfo {
struct timer_list cpu_timer;
int timer_idlecancel;
@@ -43,6 +41,7 @@ struct cpufreq_interactive_cpuinfo {
u64 freq_change_time;
u64 freq_change_time_in_idle;
u64 freq_change_time_in_iowait;
+ u64 last_high_freq_time;
struct cpufreq_policy *policy;
struct cpufreq_frequency_table *freq_table;
unsigned int target_freq;
@@ -60,6 +59,9 @@ static spinlock_t up_cpumask_lock;
static cpumask_t down_cpumask;
static spinlock_t down_cpumask_lock;
static struct mutex set_speed_lock;
+static struct mutex gov_state_lock;
+static struct kobject *interactive_kobj;
+static unsigned int active_count;
/* Go to max speed when CPU load at or above this value. */
#define DEFAULT_GO_MAXSPEED_LOAD 85
@@ -92,6 +94,24 @@ static unsigned long min_sample_time;
#define DEFAULT_TIMER_RATE 20000;
static unsigned long timer_rate;
+/*
+ * The minimum delay before frequency is allowed to raise over normal rate.
+ * Since it must remain at high frequency for a minimum of MIN_SAMPLE_TIME
+ * once it rises, setting this delay to a multiple of MIN_SAMPLE_TIME
+ * becomes the best way to enforce a square wave.
+ * e.g. 5*MIN_SAMPLE_TIME = 20% high freq duty cycle
+ */
+#define DEFAULT_HIGH_FREQ_MIN_DELAY 5*DEFAULT_MIN_SAMPLE_TIME
+static unsigned long high_freq_min_delay;
+
+/*
+ * The maximum frequency CPUs are allowed to run normally
+ * 0 if disabled
+ */
+#define DEFAULT_MAX_NORMAL_FREQ 0
+static unsigned long max_normal_freq;
+
+
/* Defines to control mid-range frequencies */
#define DEFAULT_MID_RANGE_GO_MAXSPEED_LOAD 95
@@ -274,6 +294,20 @@ static void cpufreq_interactive_timer(unsigned long data)
goto rearm;
}
+ /*
+ * Can only overclock if the delay is satisfy. Otherwise, cap it to
+ * maximum allowed normal frequency
+ */
+ if (max_normal_freq && (new_freq > max_normal_freq)) {
+ if (cputime64_sub(pcpu->timer_run_time, pcpu->last_high_freq_time)
+ < high_freq_min_delay) {
+ new_freq = max_normal_freq;
+ }
+ else {
+ pcpu->last_high_freq_time = pcpu->timer_run_time;
+ }
+ }
+
if (new_freq < pcpu->target_freq) {
pcpu->target_freq = new_freq;
spin_lock_irqsave(&down_cpumask_lock, flags);
@@ -520,220 +554,43 @@ static void cpufreq_interactive_freq_down(struct work_struct *work)
}
}
-static ssize_t show_go_maxspeed_load(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", go_maxspeed_load);
-}
-
-static ssize_t store_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;
- go_maxspeed_load = val;
- return count;
-}
-
-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)
-{
- return sprintf(buf, "%lu\n", boost_factor);
-}
-
-static ssize_t store_boost_factor(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;
- boost_factor = val;
- return count;
-}
-
-static struct global_attr boost_factor_attr = __ATTR(boost_factor, 0644,
- show_boost_factor, store_boost_factor);
-
-static ssize_t show_io_is_busy(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", io_is_busy);
-}
-
-static ssize_t store_io_is_busy(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t count)
-{
- if (!strict_strtoul(buf, 0, &io_is_busy))
- return count;
- return -EINVAL;
-}
-
-static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644,
- show_io_is_busy, store_io_is_busy);
-
-static ssize_t show_max_boost(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", max_boost);
-}
-
-static ssize_t store_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;
- max_boost = val;
- return count;
-}
-
-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)
-{
- return sprintf(buf, "%lu\n", sustain_load);
-}
-
-static ssize_t store_sustain_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;
- sustain_load = val;
- return count;
-}
-
-static struct global_attr sustain_load_attr = __ATTR(sustain_load, 0644,
- show_sustain_load, store_sustain_load);
-
-static ssize_t show_min_sample_time(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", min_sample_time);
-}
-
-static ssize_t store_min_sample_time(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;
- min_sample_time = val;
- return count;
-}
-
-static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644,
- show_min_sample_time, store_min_sample_time);
-
-static ssize_t show_timer_rate(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- return sprintf(buf, "%lu\n", timer_rate);
-}
-
-static ssize_t store_timer_rate(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;
- timer_rate = val;
- return count;
-}
-
-static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644,
- show_timer_rate, store_timer_rate);
+#define DECL_CPUFREQ_INTERACTIVE_ATTR(name) \
+static ssize_t show_##name(struct kobject *kobj, \
+ struct attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%lu\n", name); \
+} \
+\
+static ssize_t store_##name(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; \
+ name = val; \
+ return count; \
+} \
+\
+static struct global_attr name##_attr = __ATTR(name, 0644, \
+ show_##name, store_##name);
+
+DECL_CPUFREQ_INTERACTIVE_ATTR(go_maxspeed_load)
+DECL_CPUFREQ_INTERACTIVE_ATTR(midrange_freq)
+DECL_CPUFREQ_INTERACTIVE_ATTR(midrange_go_maxspeed_load)
+DECL_CPUFREQ_INTERACTIVE_ATTR(boost_factor)
+DECL_CPUFREQ_INTERACTIVE_ATTR(io_is_busy)
+DECL_CPUFREQ_INTERACTIVE_ATTR(max_boost)
+DECL_CPUFREQ_INTERACTIVE_ATTR(midrange_max_boost)
+DECL_CPUFREQ_INTERACTIVE_ATTR(sustain_load)
+DECL_CPUFREQ_INTERACTIVE_ATTR(min_sample_time)
+DECL_CPUFREQ_INTERACTIVE_ATTR(timer_rate)
+DECL_CPUFREQ_INTERACTIVE_ATTR(high_freq_min_delay)
+DECL_CPUFREQ_INTERACTIVE_ATTR(max_normal_freq)
+
+#undef DECL_CPUFREQ_INTERACTIVE_ATTR
static struct attribute *interactive_attributes[] = {
&go_maxspeed_load_attr.attr,
@@ -746,6 +603,8 @@ static struct attribute *interactive_attributes[] = {
&sustain_load_attr.attr,
&min_sample_time_attr.attr,
&timer_rate_attr.attr,
+ &high_freq_min_delay_attr.attr,
+ &max_normal_freq_attr.attr,
NULL,
};
@@ -783,7 +642,8 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
pcpu->freq_change_time_in_iowait =
get_cpu_iowait_time(j, NULL);
pcpu->time_in_iowait = pcpu->freq_change_time_in_iowait;
-
+ if (!pcpu->last_high_freq_time)
+ pcpu->last_high_freq_time = pcpu->freq_change_time;
pcpu->timer_idlecancel = 1;
pcpu->governor_enabled = 1;
smp_wmb();
@@ -792,17 +652,25 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
mod_timer(&pcpu->cpu_timer, jiffies + 2);
}
+ mutex_lock(&gov_state_lock);
+ active_count++;
/*
* Do not register the idle hook and create sysfs
* entries if we have already done so.
*/
- if (atomic_inc_return(&active_count) > 1)
- return 0;
-
- rc = sysfs_create_group(cpufreq_global_kobject,
- &interactive_attr_group);
- if (rc)
- return rc;
+ if (active_count == 1) {
+ rc = sysfs_create_group(cpufreq_global_kobject,
+ &interactive_attr_group);
+ interactive_kobj = kobject_create_and_add(
+ "gov_interactive",
+ cpufreq_global_kobject);
+ kobject_uevent(interactive_kobj, KOBJ_ADD);
+ if (rc) {
+ mutex_unlock(&gov_state_lock);
+ return rc;
+ }
+ }
+ mutex_unlock(&gov_state_lock);
break;
@@ -823,11 +691,18 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
}
flush_work(&freq_scale_down_work);
- if (atomic_dec_return(&active_count) > 0)
- return 0;
+ mutex_lock(&gov_state_lock);
+
+ active_count--;
+
+ if (active_count == 0) {
+ sysfs_remove_group(cpufreq_global_kobject,
+ &interactive_attr_group);
+ kobject_uevent(interactive_kobj, KOBJ_REMOVE);
+ kobject_put(interactive_kobj);
+ }
- sysfs_remove_group(cpufreq_global_kobject,
- &interactive_attr_group);
+ mutex_unlock(&gov_state_lock);
break;
@@ -873,6 +748,8 @@ static int __init cpufreq_interactive_init(void)
midrange_go_maxspeed_load = DEFAULT_MID_RANGE_GO_MAXSPEED_LOAD;
min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
timer_rate = DEFAULT_TIMER_RATE;
+ high_freq_min_delay = DEFAULT_HIGH_FREQ_MIN_DELAY;
+ max_normal_freq = DEFAULT_MAX_NORMAL_FREQ;
/* Initalize per-cpu timers */
for_each_possible_cpu(i) {
@@ -903,6 +780,7 @@ static int __init cpufreq_interactive_init(void)
spin_lock_init(&up_cpumask_lock);
spin_lock_init(&down_cpumask_lock);
mutex_init(&set_speed_lock);
+ mutex_init(&gov_state_lock);
idle_notifier_register(&cpufreq_interactive_idle_nb);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 1957eee7549e..d0344284a7d8 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -59,6 +59,11 @@ static int cpufreq_stats_update(unsigned int cpu)
cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, cpu);
+ if (!stat) {
+ spin_unlock(&cpufreq_stats_lock);
+ return 0;
+ }
+
if (stat->time_in_state && stat->last_index >= 0)
stat->time_in_state[stat->last_index] =
cputime64_add(stat->time_in_state[stat->last_index],
@@ -170,12 +175,17 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
*/
static void cpufreq_stats_free_table(unsigned int cpu)
{
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
+ struct cpufreq_stats *stat;
+
+ spin_lock(&cpufreq_stats_lock);
+ stat = per_cpu(cpufreq_stats_table, cpu);
+ per_cpu(cpufreq_stats_table, cpu) = NULL;
+ spin_unlock(&cpufreq_stats_lock);
+
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
- per_cpu(cpufreq_stats_table, cpu) = NULL;
}
/* must be called early in the CPU removal sequence (before
@@ -299,19 +309,23 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
if (val != CPUFREQ_POSTCHANGE)
return 0;
+ cpufreq_stats_update(freq->cpu);
+
+ spin_lock(&cpufreq_stats_lock);
stat = per_cpu(cpufreq_stats_table, freq->cpu);
- if (!stat)
+ if (!stat) {
+ spin_unlock(&cpufreq_stats_lock);
return 0;
+ }
old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
- cpufreq_stats_update(freq->cpu);
-
- if (old_index == new_index)
+ if (old_index == new_index) {
+ spin_unlock(&cpufreq_stats_lock);
return 0;
+ }
- spin_lock(&cpufreq_stats_lock);
stat->last_index = new_index;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
if (old_index >= 0 && new_index >= 0)
diff --git a/drivers/cpuquiet/governor.c b/drivers/cpuquiet/governor.c
index 7895fccc7f42..176ba3bd705f 100644
--- a/drivers/cpuquiet/governor.c
+++ b/drivers/cpuquiet/governor.c
@@ -100,3 +100,17 @@ void cpuquiet_unregister_governor(struct cpuquiet_governor *gov)
list_del(&gov->governor_list);
mutex_unlock(&cpuquiet_lock);
}
+
+void cpuquiet_device_busy(void)
+{
+ if (cpuquiet_curr_governor &&
+ cpuquiet_curr_governor->device_busy_notification)
+ cpuquiet_curr_governor->device_busy_notification();
+}
+
+void cpuquiet_device_free(void)
+{
+ if (cpuquiet_curr_governor &&
+ cpuquiet_curr_governor->device_free_notification)
+ cpuquiet_curr_governor->device_free_notification();
+}
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index e244cfcdd505..7ab59856d755 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -15,5 +15,7 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+CFLAGS_tegra-aes.o = -Werror
obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+CFLAGS_tegra-se.o = -Werror
obj-$(CONFIG_CRYPTO_DEV_TEGRA_SE) += tegra-se.o
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4ef6785f446b..7754ff0c239d 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -1,5 +1,7 @@
# generic gpio support: platform drivers, dedicated expander chips, etc
+GCOV_PROFILE := y
+
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += gpiolib.o
@@ -48,6 +50,7 @@ obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
+CFLAGS_gpio-tegra.o = -Werror
obj-$(CONFIG_ARCH_TEGRA) += gpio-tegra.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 49abdf016b26..c1a80fb8578d 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -6,7 +6,7 @@
* Author:
* Erik Gilling <konkers@google.com>
*
- * 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
@@ -314,6 +314,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
+ tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0);
+ tegra_gpio_enable(gpio);
+
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
__irq_set_handler_locked(d->irq, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -390,6 +393,9 @@ static int tegra_gpio_suspend(void)
bank->oe[p] = __raw_readl(GPIO_OE(gpio));
bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio));
bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio));
+
+ /* disable gpio interrupts that are not wake sources */
+ __raw_writel(bank->wake_enb[p], GPIO_INT_ENB(gpio));
}
}
local_irq_restore(flags);
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index d9797487180d..66af4257ddc7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -126,6 +126,7 @@ obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
obj-$(CONFIG_SENSORS_INA219) += ina219.o
obj-$(CONFIG_SENSORS_INA230) += ina230.o
+CFLAGS_tegra-tsensor.o = -Werror
obj-$(CONFIG_SENSORS_TEGRA_TSENSOR) += tegra-tsensor.o
obj-$(CONFIG_PMBUS) += pmbus/
diff --git a/drivers/hwmon/tegra-tsensor.c b/drivers/hwmon/tegra-tsensor.c
index 1c372a4bcce5..c5b16fe97063 100644
--- a/drivers/hwmon/tegra-tsensor.c
+++ b/drivers/hwmon/tegra-tsensor.c
@@ -1049,11 +1049,16 @@ static void get_quadratic_roots(struct tegra_tsensor_data *data,
and
(-(2*m*B+n)-sqrt(((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp))))/(2*m*A)
+ After simplify ((2*m*B+n)^2-4*m(m*B^2+n*B+p-temp)),
+ Roots are:
+ (-(2*m*B+n)+sqrt((n^2-4*m(p-temp))))/(2*m*A)
+ and
+ (-(2*m*B+n)-sqrt((n^2-4*m(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_4m_p_minusTemp;
+ int v_e_minus6_n2;
int v_e_minus6_b2_minus4ac;
int v_e_minus6_sqrt_b2_minus4ac;
s64 v_e_minus12_2mA;
@@ -1091,61 +1096,38 @@ static void get_quadratic_roots(struct tegra_tsensor_data *data,
v_e_minus12_2mA = temp_64;
/* computed 2mA */
- /* m * B^2 calculation */
- temp_64 = ((s64)data->B_e_minus6 * (s64)data->B_e_minus6);
+ temp_64 = ((s64)data->n_e_minus6 * (s64)data->n_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_n2 = (s32)temp_64;
+ /* computed n^2 */
+
+ v_e_minus6_4m_p_minusTemp = data->p_e_minus2 - (temp * 100);
+ v_e_minus6_4m_p_minusTemp *= 4 * data->m_e_minus6;
+ v_e_minus6_4m_p_minusTemp = DIV_ROUND_CLOSEST(
+ v_e_minus6_4m_p_minusTemp,100);
+ /* computed 4m*(p-T)*/
+
+ v_e_minus6_b2_minus4ac = (v_e_minus6_n2 - v_e_minus6_4m_p_minusTemp);
+
+ /* To preserve 1 decimal digits for sqrt(v_e_minus6_b2_minus4ac),
+ Make it 100 times, so
+ v_e_minus6_sqrt_b2_minus4ac=(int_sqrt(v_e_minus6_b2_minus4ac *100)*10^6)
+ /sqrt(10^6 * 100)
+ To avoid overflow,Simplify it to be:
+ v_e_minus6_sqrt_b2_minus4ac =(int_sqrt(v_e_minus6_b2_minus4ac *100)*100)
+ */
- v_e_minus6_sqrt_b2_minus4ac = DIV_ROUND_CLOSEST(
- (int_sqrt(v_e_minus6_b2_minus4ac)*1000000),
- int_sqrt(1000000));
+ v_e_minus6_sqrt_b2_minus4ac = (int_sqrt(v_e_minus6_b2_minus4ac * 100)
+ * 100);
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_minus12, data->B_e_minus6,
data->m_e_minus6,
data->n_e_minus6, data->p_e_minus2, (int)temp);
- dev_dbg(data->hwmon_dev, "2mB_n=%d, 2mA=%lld, mB2_nB_p_minusTemp=%d,"
+ dev_dbg(data->hwmon_dev, "2mB_n=%d, 2mA=%lld, 4m_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_minus12_2mA, v_e_minus6_4m_p_minusTemp,
v_e_minus6_b2_minus4ac);
temp_64=(s64)(-v_e_minus6_2mB_n - v_e_minus6_sqrt_b2_minus4ac) * 1000000;
@@ -1979,6 +1961,8 @@ static int __devexit tegra_tsensor_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+
static void save_tsensor_regs(struct tegra_tsensor_data *data)
{
int i;
@@ -2005,7 +1989,7 @@ static void restore_tsensor_regs(struct tegra_tsensor_data *data)
}
}
-#ifdef CONFIG_PM
+
static int tsensor_suspend(struct platform_device *pdev,
pm_message_t state)
{
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ce35a87a7012..381a6ca1a6bb 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -62,7 +62,9 @@ obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
+CFLAGS_i2c-tegra.o = -Werror
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
+CFLAGS_i2c-slave-tegra.o = -Werror
obj-$(CONFIG_I2C_SLAVE_TEGRA) += i2c-slave-tegra.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 1358dc70b0e4..b3c7a762760a 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/i2c-tegra.h>
#include <linux/of_i2c.h>
@@ -129,6 +130,15 @@ enum msg_end_type {
struct tegra_i2c_dev;
+/**
+ * struct tegra_i2c_hw_feature : Different HW support on Tegra
+ * @has_continue_xfer_support: Continue transfer supports.
+ */
+
+struct tegra_i2c_hw_feature {
+ bool has_continue_xfer_support;
+};
+
struct tegra_i2c_bus {
struct tegra_i2c_dev *dev;
const struct tegra_pingroup_config *mux;
@@ -142,10 +152,10 @@ struct tegra_i2c_bus {
/**
* struct tegra_i2c_dev - per device i2c context
* @dev: device reference for power management
+ * @hw: Tegra i2c hw feature.
* @adapter: core i2c layer adapter information
- * @clk: clock reference for i2c controller
- * @i2c_clk: clock reference for i2c bus
- * @iomem: memory resource for registers
+ * @div_clk: clock reference for div clock of i2c controller.
+ * @fast_clk: clock reference for fast clock of i2c controller.
* @base: ioremapped registers cookie
* @cont_id: i2c controller id, used for for packet header
* @irq: irq number of transfer complete interrupt
@@ -160,9 +170,9 @@ struct tegra_i2c_bus {
*/
struct tegra_i2c_dev {
struct device *dev;
+ struct tegra_i2c_hw_feature *hw;
struct clk *div_clk;
struct clk *fast_clk;
- struct resource *iomem;
struct rt_mutex dev_lock;
spinlock_t fifo_lock;
void __iomem *base;
@@ -170,7 +180,6 @@ struct tegra_i2c_dev {
int irq;
bool irq_disabled;
int is_dvc;
- bool is_slave;
struct completion msg_complete;
int msg_err;
u8 *msg_buf;
@@ -235,6 +244,10 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
unsigned long reg)
{
writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
+
+ /* Read back register to make sure that register writes completed */
+ if (reg != I2C_TX_FIFO)
+ readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg));
}
static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg)
@@ -442,13 +455,13 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev)
ret = clk_enable(i2c_dev->fast_clk);
if (ret < 0) {
dev_err(i2c_dev->dev,
- "Error in enabling fast clock err %d\n", ret);
+ "Enabling fast clk failed, err %d\n", ret);
return ret;
}
ret = clk_enable(i2c_dev->div_clk);
if (ret < 0) {
dev_err(i2c_dev->dev,
- "Error in enabling div clock err %d\n", ret);
+ "Enabling div clk failed, err %d\n", ret);
clk_disable(i2c_dev->fast_clk);
}
return ret;
@@ -465,12 +478,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
u32 val;
int err = 0;
- if (!i2c_dev->is_clkon_always)
- tegra_i2c_clock_enable(i2c_dev);
-
- /* Interrupt generated before sending stop signal so
- * wait for some time so that stop signal can be send proerly */
- mdelay(1);
+ tegra_i2c_clock_enable(i2c_dev);
tegra_periph_reset_assert(i2c_dev->div_clk);
udelay(2);
@@ -499,14 +507,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
- if (i2c_dev->is_slave)
+ if (!i2c_dev->is_dvc)
tegra_i2c_slave_init(i2c_dev);
if (tegra_i2c_flush_fifos(i2c_dev))
err = -ETIMEDOUT;
- if (!i2c_dev->is_clkon_always)
- tegra_i2c_clock_disable(i2c_dev);
+ tegra_i2c_clock_disable(i2c_dev);
if (i2c_dev->irq_disabled) {
i2c_dev->irq_disabled = 0;
@@ -595,12 +602,9 @@ 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);
@@ -636,16 +640,13 @@ 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;
@@ -664,10 +665,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
tegra_i2c_flush_fifos(i2c_dev);
- /* Toggle the direction flag if rev dir is selected */
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- msg->flags ^= I2C_M_RD;
-
i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len;
i2c_dev->msg_err = I2C_ERR_NONE;
@@ -728,10 +725,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
if (i2c_dev->is_dvc)
dvc_i2c_mask_irq(i2c_dev, DVC_CTRL_REG3_I2C_DONE_INTR_EN);
- /* Restore the message flag */
- if (msg->flags & I2C_M_REV_DIR_ADDR)
- msg->flags ^= I2C_M_RD;
-
if (WARN_ON(ret == 0)) {
dev_err(i2c_dev->dev,
"i2c transfer timed out, addr 0x%04x, data 0x%02x\n",
@@ -756,6 +749,14 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
}
}
+ /*
+ * NACK interrupt is generated before the I2C controller generates the
+ * STOP condition on the bus. So wait for 2 clock periods before resetting
+ * the controller so that STOP condition has been delivered properly.
+ */
+ if (i2c_dev->msg_err == I2C_ERR_NO_ACK)
+ udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->last_bus_clk_rate));
+
tegra_i2c_init(i2c_dev);
if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
@@ -785,6 +786,17 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
return -EBUSY;
}
+ /* Support I2C_M_NOSTART only if HW support continue xfer. */
+ for (i = 0; i < num - 1; i++) {
+ if ((msgs[i + 1].flags & I2C_M_NOSTART) &&
+ !i2c_dev->hw->has_continue_xfer_support) {
+ dev_err(i2c_dev->dev,
+ "mesg %d have illegal flag\n", i + 1);
+ rt_mutex_unlock(&i2c_dev->dev_lock);
+ return -EINVAL;
+ }
+ }
+
if (i2c_dev->last_mux != i2c_bus->mux) {
tegra_pinmux_set_safe_pinmux_table(i2c_dev->last_mux,
i2c_dev->last_mux_len);
@@ -802,8 +814,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
i2c_dev->msgs = msgs;
i2c_dev->msgs_num = num;
- if (!i2c_dev->is_clkon_always)
- tegra_i2c_clock_enable(i2c_dev);
+ pm_runtime_get_sync(&adap->dev);
+ tegra_i2c_clock_enable(i2c_dev);
for (i = 0; i < num; i++) {
enum msg_end_type end_type = MSG_END_STOP;
@@ -818,8 +830,8 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
break;
}
- if (!i2c_dev->is_clkon_always)
- tegra_i2c_clock_disable(i2c_dev);
+ tegra_i2c_clock_disable(i2c_dev);
+ pm_runtime_put(&adap->dev);
rt_mutex_unlock(&i2c_dev->dev_lock);
@@ -840,16 +852,32 @@ static const struct i2c_algorithm tegra_i2c_algo = {
.functionality = tegra_i2c_func,
};
-static int tegra_i2c_probe(struct platform_device *pdev)
+static struct tegra_i2c_hw_feature tegra20_i2c_hw = {
+ .has_continue_xfer_support = false,
+};
+
+static struct tegra_i2c_hw_feature tegra30_i2c_hw = {
+ .has_continue_xfer_support = true,
+};
+
+#if defined(CONFIG_OF)
+/* Match table for of_platform binding */
+static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+#endif
+
+static int __devinit tegra_i2c_probe(struct platform_device *pdev)
{
struct tegra_i2c_dev *i2c_dev;
struct tegra_i2c_platform_data *plat = pdev->dev.platform_data;
struct resource *res;
- struct resource *iomem;
struct clk *div_clk;
struct clk *fast_clk = NULL;
const unsigned int *prop;
- void *base;
+ void __iomem *base;
int irq;
int nbus;
int i = 0;
@@ -873,56 +901,54 @@ static int tegra_i2c_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "no mem resource\n");
return -EINVAL;
}
- iomem = request_mem_region(res->start, resource_size(res), pdev->name);
- if (!iomem) {
- dev_err(&pdev->dev, "I2C region already claimed\n");
- return -EBUSY;
- }
- base = ioremap(iomem->start, resource_size(iomem));
+ base = devm_request_and_ioremap(&pdev->dev, res);
if (!base) {
- dev_err(&pdev->dev, "Cannot ioremap I2C region\n");
- return -ENOMEM;
+ dev_err(&pdev->dev, "Cannot request/ioremap I2C registers\n");
+ return -EADDRNOTAVAIL;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(&pdev->dev, "no irq resource\n");
- ret = -EINVAL;
- goto err_iounmap;
+ return -EINVAL;
}
irq = res->start;
- div_clk = clk_get(&pdev->dev, "i2c-div");
+ div_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(div_clk)) {
dev_err(&pdev->dev, "missing controller clock");
- ret = PTR_ERR(div_clk);
- goto err_release_region;
+ return PTR_ERR(div_clk);
}
- fast_clk = clk_get(&pdev->dev, "i2c-fast");
+ fast_clk = devm_clk_get(&pdev->dev, "fast-clk");
if (IS_ERR(fast_clk)) {
dev_err(&pdev->dev, "missing controller fast clock");
- ret = PTR_ERR(fast_clk);
- goto fast_clk_err;
+ return PTR_ERR(fast_clk);
}
- i2c_dev = kzalloc(sizeof(struct tegra_i2c_dev) +
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2c_dev) +
(nbus-1) * sizeof(struct tegra_i2c_bus), GFP_KERNEL);
if (!i2c_dev) {
- ret = -ENOMEM;
- goto err_clk_put;
+ dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev");
+ return -ENOMEM;
}
i2c_dev->base = base;
i2c_dev->div_clk = div_clk;
i2c_dev->fast_clk = fast_clk;
- i2c_dev->iomem = iomem;
i2c_dev->irq = irq;
i2c_dev->cont_id = pdev->id;
i2c_dev->dev = &pdev->dev;
i2c_dev->is_clkon_always = plat->is_clkon_always;
+
+#ifdef ARCH_TEGRA_2x_SOC
+ i2c_dev->hw = &tegra20_i2c_hw;
+#else
+ i2c_dev->hw = &tegra30_i2c_hw;
+#endif
+
i2c_dev->last_bus_clk_rate = 100000; /* default clock rate */
if (plat) {
i2c_dev->last_bus_clk_rate = plat->bus_clk_rate[0];
@@ -933,6 +959,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
"clock-frequency", NULL);
if (prop)
i2c_dev->last_bus_clk_rate = be32_to_cpup(prop);
+
+ /* FIXME! Populate the Tegra30 and then support M_NOSTART */
+ i2c_dev->hw = &tegra20_i2c_hw;
}
i2c_dev->is_high_speed_enable = plat->is_high_speed_enable;
@@ -948,9 +977,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->arb_recovery = plat->arb_recovery;
init_completion(&i2c_dev->msg_complete);
- if (irq == INT_I2C || irq == INT_I2C2 || irq == INT_I2C3)
- i2c_dev->is_slave = true;
-
platform_set_drvdata(pdev, i2c_dev);
if (i2c_dev->is_clkon_always)
@@ -959,15 +985,17 @@ static int tegra_i2c_probe(struct platform_device *pdev)
ret = tegra_i2c_init(i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize i2c controller");
- goto err_free;
+ return ret;
}
- ret = request_irq(i2c_dev->irq, tegra_i2c_isr, 0, pdev->name, i2c_dev);
+ ret = devm_request_irq(&pdev->dev, i2c_dev->irq,
+ tegra_i2c_isr, 0, pdev->name, i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq);
- goto err_free;
+ return ret;
}
+ pm_runtime_enable(&pdev->dev);
for (i = 0; i < nbus; i++) {
struct tegra_i2c_bus *i2c_bus = &i2c_dev->busses[i];
@@ -1004,49 +1032,36 @@ static int tegra_i2c_probe(struct platform_device *pdev)
goto err_del_bus;
}
of_i2c_register_devices(&i2c_bus->adapter);
+ pm_runtime_enable(&i2c_bus->adapter.dev);
i2c_dev->bus_count++;
}
+
return 0;
err_del_bus:
while (i2c_dev->bus_count--)
i2c_del_adapter(&i2c_dev->busses[i2c_dev->bus_count].adapter);
- free_irq(i2c_dev->irq, i2c_dev);
-err_free:
- kfree(i2c_dev);
-err_clk_put:
- clk_put(fast_clk);
-fast_clk_err:
- clk_put(div_clk);
-err_release_region:
- release_mem_region(iomem->start, resource_size(iomem));
-err_iounmap:
- iounmap(base);
return ret;
}
-static int tegra_i2c_remove(struct platform_device *pdev)
+static int __devexit tegra_i2c_remove(struct platform_device *pdev)
{
struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
- while (i2c_dev->bus_count--)
+
+ while (i2c_dev->bus_count--) {
i2c_del_adapter(&i2c_dev->busses[i2c_dev->bus_count].adapter);
+ pm_runtime_disable(&i2c_dev->busses[i2c_dev->bus_count].adapter.dev);
+ }
if (i2c_dev->is_clkon_always)
tegra_i2c_clock_disable(i2c_dev);
-
- free_irq(i2c_dev->irq, i2c_dev);
- clk_put(i2c_dev->div_clk);
- clk_put(i2c_dev->fast_clk);
- release_mem_region(i2c_dev->iomem->start,
- resource_size(i2c_dev->iomem));
- iounmap(i2c_dev->base);
- kfree(i2c_dev);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int tegra_i2c_suspend_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1088,34 +1103,23 @@ static int tegra_i2c_resume_noirq(struct device *dev)
return 0;
}
-static const struct dev_pm_ops tegra_i2c_dev_pm_ops = {
+static const struct dev_pm_ops tegra_i2c_pm = {
.suspend_noirq = tegra_i2c_suspend_noirq,
.resume_noirq = tegra_i2c_resume_noirq,
};
-#define TEGRA_I2C_DEV_PM_OPS (&tegra_i2c_dev_pm_ops)
-#else
-#define TEGRA_I2C_DEV_PM_OPS NULL
-#endif
-
-#if defined(CONFIG_OF)
-/* Match table for of_platform binding */
-static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
- { .compatible = "nvidia,tegra20-i2c", },
- {},
-};
-MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+#define TEGRA_I2C_PM (&tegra_i2c_pm)
#else
-#define tegra_i2c_of_match NULL
+#define TEGRA_I2C_PM NULL
#endif
static struct platform_driver tegra_i2c_driver = {
.probe = tegra_i2c_probe,
- .remove = tegra_i2c_remove,
+ .remove = __devexit_p(tegra_i2c_remove),
.driver = {
.name = "tegra-i2c",
.owner = THIS_MODULE,
- .of_match_table = tegra_i2c_of_match,
- .pm = TEGRA_I2C_DEV_PM_OPS,
+ .of_match_table = of_match_ptr(tegra_i2c_of_match),
+ .pm = TEGRA_I2C_PM,
},
};
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 23b440a4c27c..aced870f4e9d 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
+CFLAGS_tegra-kbc.o = -Werror
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ad21ef9c0105..6721a1fd2456 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2010 Samsung Electronics Co.Ltd
* Copyright (C) 2011 Atmel Corporation
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (C) 2011-2012 NVIDIA Corporation
* Author: Joonyoung Shim <jy0922.shim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -25,6 +25,8 @@
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
#endif
+#define CREATE_TRACE_POINTS
+#include <trace/events/nvevent.h>
/* Family ID */
#define MXT224_ID 0x80
@@ -716,6 +718,7 @@ static void mxt_input_touchevent(struct mxt_data *data,
finger[id].area = area;
finger[id].pressure = pressure;
+ trace_nvevent_irq_data_submit("mxt_input_touchevent");
mxt_input_report(data, id);
}
@@ -728,11 +731,15 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
int touchid;
u8 reportid;
+ trace_nvevent_irq_data_read_start_series("mxt_input_interrupt");
do {
+ trace_nvevent_irq_data_read_start_single("mxt_input_interrupt");
if (mxt_read_message(data, &message)) {
dev_err(dev, "Failed to read message\n");
goto end;
}
+ trace_nvevent_irq_data_read_finish_single(
+ "mxt_input_interrupt");
reportid = message.reportid;
@@ -751,6 +758,7 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)
} else if (reportid != MXT_RPTID_NOMSG)
mxt_dump_message(dev, &message);
} while (reportid != MXT_RPTID_NOMSG);
+ trace_nvevent_irq_data_read_finish_series("mxt_input_interrupt");
end:
return IRQ_HANDLED;
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 7ad7a3bc1242..ed59619d1af8 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -8,5 +8,7 @@ obj-$(CONFIG_IRQ_REMAP) += intr_remapping.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o
obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
+CFLAGS_tegra-gart.o = -Werror
obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
+CFLAGS_tegra-smmu.o = -Werror
obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 7b5ef3ffb7d0..25bff5c02bb4 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -320,8 +320,15 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
val = smmu_read(smmu, offs);
if (on) {
#if !defined(SKIP_SWGRP_CHECK)
- if (WARN_ON(val & mask))
- goto err_hw_busy;
+ if (WARN_ON(val & mask)) {
+ for_each_set_bit(i, &map, HWGRP_COUNT) {
+ offs = HWGRP_ASID_REG(i);
+ val = smmu_read(smmu, offs);
+ val &= ~mask;
+ smmu_write(smmu, val, offs);
+ }
+ return -EBUSY;
+ }
#endif
val |= mask;
} else {
@@ -336,14 +343,6 @@ static int __smmu_client_set_hwgrp(struct smmu_client *c,
c->hwgrp = map;
return 0;
-err_hw_busy:
- for_each_set_bit(i, &map, HWGRP_COUNT) {
- offs = HWGRP_ASID_REG(i);
- val = smmu_read(smmu, offs);
- val &= ~mask;
- smmu_write(smmu, val, offs);
- }
- return -EBUSY;
}
static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
diff --git a/drivers/media/video/tegra/ad5816.c b/drivers/media/video/tegra/ad5816.c
index 9e31acc33cc3..6fdb9f184614 100644
--- a/drivers/media/video/tegra/ad5816.c
+++ b/drivers/media/video/tegra/ad5816.c
@@ -96,12 +96,14 @@
#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_SLEW_RATE 1
+#define AD5816_ACTUATOR_RANGE 1023
+#define AD5816_SETTLETIME 50
#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
+#define AD5816_POS_LOW_DEFAULT 0
+#define AD5816_POS_HIGH_DEFAULT 1023
+#define AD5816_POS_CLAMP 0x03ff
/* Need to decide exact value of VCM_THRESHOLD and its use */
/* define AD5816_VCM_THRESHOLD 20 */
@@ -140,6 +142,7 @@ struct ad5816_info {
struct ad5816_info *s_info;
struct nvc_focus_nvc nvc;
struct nvc_focus_cap cap;
+ struct nv_focuser_config nv_config;
struct ad5816_pdata_info config;
};
@@ -154,10 +157,12 @@ static struct ad5816_pdata_info ad5816_default_info = {
static struct nvc_focus_cap ad5816_default_cap = {
.version = NVC_FOCUS_CAP_VER2,
+ .slew_rate = AD5816_SLEW_RATE,
.actuator_range = AD5816_ACTUATOR_RANGE,
.settle_time = AD5816_SETTLETIME,
.focus_macro = AD5816_FOCUS_MACRO,
.focus_infinity = AD5816_FOCUS_INFINITY,
+ .focus_hyper = AD5816_FOCUS_INFINITY,
};
static struct nvc_focus_nvc ad5816_default_nvc = {
@@ -637,28 +642,76 @@ static int ad5816_position_rd(struct ad5816_info *info, unsigned *position)
int err = 0;
err = ad5816_i2c_rd8(info, 0, VCM_CODE_MSB, &t1);
- pos = t1 & 0x03;
+ pos = t1;
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;
+ if (pos < info->config.pos_low)
+ pos = info->config.pos_low;
+ else if (pos > info->config.pos_high)
+ pos = info->config.pos_high;
+
+ *position = pos;
+
+ return err;
}
-static int ad5816_position_wr(struct ad5816_info *info, unsigned position)
+static int ad5816_position_wr(struct ad5816_info *info, s32 position)
{
- u16 data;
+ s16 data;
- position = position + info->config.pos_low;
- if(position > info->config.pos_high)
- position = info->config.pos_high;
+ ad5816_set_arc_mode(info);
- data = position & 0x03ff;
+ if (position > info->config.pos_high)
+ return -EINVAL;
+ data = position & AD5816_POS_CLAMP;
return ad5816_i2c_wr16(info, VCM_CODE_MSB, data);
+
+}
+
+static void ad5816_get_focuser_capabilities(struct ad5816_info *info)
+{
+ memset(&info->nv_config, 0, sizeof(info->nv_config));
+
+ info->nv_config.focal_length = info->nvc.focal_length;
+ info->nv_config.fnumber = info->nvc.fnumber;
+ info->nv_config.max_aperture = info->nvc.fnumber;
+ info->nv_config.range_ends_reversed = 0;
+ info->nv_config.settle_time = info->cap.settle_time;
+
+ info->nv_config.pos_working_low = AF_POS_INVALID_VALUE;
+ info->nv_config.pos_working_high = AF_POS_INVALID_VALUE;
+
+ info->nv_config.pos_actual_low = info->config.pos_low;
+ info->nv_config.pos_actual_high = info->config.pos_high;
+
+ info->nv_config.slew_rate = info->cap.slew_rate;
+ info->nv_config.circle_of_confusion = -1;
+ info->nv_config.num_focuser_sets = 1;
+ info->nv_config.focuser_set[0].macro = info->cap.focus_macro;
+ info->nv_config.focuser_set[0].hyper = info->cap.focus_hyper;
+ info->nv_config.focuser_set[0].inf = info->cap.focus_infinity;
+ info->nv_config.focuser_set[0].settle_time = info->cap.settle_time;
+}
+
+static int ad5816_set_focuser_capabilities(struct ad5816_info *info,
+ struct nvc_param *params)
+{
+ if (copy_from_user(&info->nv_config, (const void __user *)params->p_value,
+ sizeof(struct nv_focuser_config))) {
+ dev_err(&info->i2c_client->dev, "%s Error: copy_from_user bytes %d\n",
+ __func__, sizeof(struct nv_focuser_config));
+ return -EFAULT;
+ }
+
+ /* set pre-set value, as currently ODM sets incorrect value */
+ info->cap.settle_time = AD5816_SETTLETIME;
+
+ dev_dbg(&info->i2c_client->dev, "%s: copy_from_user bytes %d info->cap.settle_time %d\n",
+ __func__, sizeof(struct nv_focuser_config), info->cap.settle_time);
+
+ return 0;
}
static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
@@ -706,13 +759,10 @@ static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
__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);
+ ad5816_get_focuser_capabilities(info);
+ data_ptr = &info->nv_config;
+ data_size = sizeof(info->nv_config);
dev_err(&info->i2c_client->dev, "%s CAPS\n", __func__);
break;
case NVC_PARAM_STS:
@@ -745,16 +795,16 @@ static int ad5816_param_rd(struct ad5816_info *info, unsigned long arg)
}
static int ad5816_param_wr_s(struct ad5816_info *info,
- struct nvc_param *params, u32 u32val)
+ struct nvc_param *params, s32 s32val)
{
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);
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n", __func__, s32val);
+ err = ad5816_position_wr(info, s32val);
return err;
case NVC_PARAM_RESET:
- err = ad5816_reset(info, u32val);
+ err = ad5816_reset(info, s32val);
dev_dbg(&info->i2c_client->dev, "%s RESET: %d\n", __func__, err);
return err;
case NVC_PARAM_SELF_TEST:
@@ -773,7 +823,7 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
{
struct nvc_param params;
u8 u8val;
- u32 u32val;
+ s32 s32val;
int err = 0;
if (copy_from_user(&params, (const void __user *)arg,
sizeof(struct nvc_param))) {
@@ -781,11 +831,11 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
__func__, __LINE__);
return -EFAULT;
}
- if (copy_from_user(&u32val, (const void __user *)params.p_value, sizeof(u32val))) {
+ if (copy_from_user(&s32val, (const void __user *)params.p_value, sizeof(s32val))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n", __func__, __LINE__);
return -EFAULT;
}
- u8val = (u8)u32val;
+ u8val = (u8)s32val;
/* parameters independent of sync mode */
switch (params.param) {
case NVC_PARAM_STEREO:
@@ -833,7 +883,7 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
/* 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);
+ err = ad5816_position_wr(info->s_info, (s32)info->pos);
if (!err) {
info->s_mode = u8val;
info->s_info->s_mode = u8val;
@@ -854,20 +904,29 @@ static int ad5816_param_wr(struct ad5816_info *info, unsigned long arg)
if (info->pdata->cfg & NVC_CFG_NOERR)
return 0;
return err;
+
+ case NVC_PARAM_CAPS:
+ if (ad5816_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) {
case NVC_SYNC_OFF:
case NVC_SYNC_MASTER:
- return ad5816_param_wr_s(info, &params, u32val);
+ return ad5816_param_wr_s(info, &params, s32val);
case NVC_SYNC_SLAVE:
- return ad5816_param_wr_s(info->s_info, &params, u32val);
+ return ad5816_param_wr_s(info->s_info, &params, s32val);
case NVC_SYNC_STEREO:
- err = ad5816_param_wr_s(info, &params, u32val);
+ err = ad5816_param_wr_s(info, &params, s32val);
if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
err |= ad5816_param_wr_s(info->s_info,
&params,
- u32val);
+ s32val);
return err;
default:
dev_err(&info->i2c_client->dev, "%s %d internal err\n",
@@ -886,10 +945,14 @@ static long ad5816_ioctl(struct file *file,
int err = 0;
switch (cmd) {
case NVC_IOCTL_PARAM_WR:
+ ad5816_pm_dev_wr(info, NVC_PWR_ON);
err = ad5816_param_wr(info, arg);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
return err;
case NVC_IOCTL_PARAM_RD:
+ ad5816_pm_dev_wr(info, NVC_PWR_ON);
err = ad5816_param_rd(info, arg);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
return err;
case NVC_IOCTL_PWR_WR:
/* This is a Guaranteed Level of Service (GLOS) call */
@@ -1032,8 +1095,8 @@ static int ad5816_open(struct inode *inode, struct file *file)
}
file->private_data = info;
ad5816_pm_dev_wr(info, NVC_PWR_ON);
- /* set ARC Mode to ensure faster focus */
- ad5816_set_arc_mode(info);
+ ad5816_position_wr(info, info->cap.focus_infinity);
+ ad5816_pm_dev_wr(info, NVC_PWR_OFF);
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
return 0;
diff --git a/drivers/media/video/tegra/ar0832_main.c b/drivers/media/video/tegra/ar0832_main.c
index 4da9f7e833b9..b1f43da22ec8 100644
--- a/drivers/media/video/tegra/ar0832_main.c
+++ b/drivers/media/video/tegra/ar0832_main.c
@@ -23,10 +23,12 @@
#include <linux/regulator/consumer.h>
#include <media/ar0832_main.h>
+
#define POS_ACTUAL_LOW 0
#define POS_ACTUAL_HIGH 255
#define SETTLE_TIME 100
-#define SLEW_RATE_DEFAULT 1
+#define AR0832_SLEW_RATE_DISABLED 0
+#define AR0832_SLEW_RATE_SLOWEST 7
struct ar0832_sensor_info {
@@ -1930,13 +1932,26 @@ static int ar0832_focuser_set_config(struct ar0832_dev *dev)
struct i2c_client *i2c_client = dev->i2c_client;
struct ar0832_reg reg_vcm_ctrl, reg_vcm_step_time;
int ret = 0;
- u8 vcm_slew = 1;
+ u8 vcm_slew;
+ u16 vcm_control_data;
+ u16 vcm_step_time = 1024;
+
+ /* slew_rate of disabled (0) or default value (1) will disable */
+ /* the slew rate in this case. Any value of 2 onwards will enable */
+ /* the slew rate to a different degree */
+ if (dev->focuser_info->config.slew_rate == SLEW_RATE_DISABLED ||
+ dev->focuser_info->config.slew_rate == SLEW_RATE_DEFAULT)
+ vcm_slew = AR0832_SLEW_RATE_DISABLED;
+ else
+ vcm_slew = dev->focuser_info->config.slew_rate - 1;
+
+ if (vcm_slew > AR0832_SLEW_RATE_SLOWEST)
+ vcm_slew = AR0832_SLEW_RATE_SLOWEST;
/* bit15(0x80) means that VCM driver enable bit. */
/* bit3(0x08) means that keep VCM(AF position) */
/* while sensor is in soft standby mode during mode transitions. */
- u16 vcm_control_data = (0x80 << 8 | (0x08 | (vcm_slew & 0x07)));
- u16 vcm_step_time = 1024;
+ vcm_control_data = (0x80 << 8 | (0x08 | (vcm_slew & 0x07)));
ar0832_get_focuser_vcm_control_regs(&reg_vcm_ctrl, vcm_control_data);
ret = ar0832_write_reg16(dev->i2c_client, reg_vcm_ctrl.addr,
@@ -2422,7 +2437,7 @@ static void ar0832_create_debugfs(struct ar0832_dev *dev)
goto remove_debugfs;
ret = debugfs_create_file("test_pattern",
- S_IWUGO | S_IRUGO,
+ S_IWUSR | S_IRUGO,
dev->debugdir, dev,
&ar0832_debugfs_fops);
if (!ret)
diff --git a/drivers/media/video/tegra/nvavp/nvavp_dev.c b/drivers/media/video/tegra/nvavp/nvavp_dev.c
index 9a54f8e3d025..4501abb9a735 100644
--- a/drivers/media/video/tegra/nvavp/nvavp_dev.c
+++ b/drivers/media/video/tegra/nvavp/nvavp_dev.c
@@ -1,7 +1,7 @@
/*
* drivers/media/video/tegra/nvavp/nvavp_dev.c
*
- * Copyright (C) 2011-2012 NVIDIA Corp.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* 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
@@ -101,6 +101,10 @@ struct nvavp_info {
struct clk *bsev_clk;
struct clk *vde_clk;
struct clk *cop_clk;
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ struct clk *bsea_clk;
+ struct clk *vcp_clk;
+#endif
/* used for dvfs */
struct clk *sclk;
@@ -115,6 +119,7 @@ struct nvavp_info {
int video_initialized;
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
int audio_initialized;
+ struct work_struct app_notify_work;
#endif
struct work_struct clock_disable_work;
@@ -263,14 +268,26 @@ static void nvavp_clks_disable(struct nvavp_info *nvavp)
}
}
-static u32 nvavp_check_idle(struct nvavp_info *nvavp)
+static u32 nvavp_check_idle(struct nvavp_info *nvavp, int channel_id)
{
- struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, NVAVP_VIDEO_CHANNEL);
+ struct nvavp_channel *channel_info = nvavp_get_channel_info(nvavp, channel_id);
struct nv_e276_control *control = channel_info->os_control;
return (control->put == control->get) ? 1 : 0;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static void app_notify_handler(struct work_struct *work)
+{
+ struct nvavp_info *nvavp;
+
+ nvavp = container_of(work, struct nvavp_info,
+ app_notify_work);
+
+ kobject_uevent(&nvavp->nvhost_dev->dev.kobj, KOBJ_CHANGE);
+}
+#endif
+
static void clock_disable_handler(struct work_struct *work)
{
struct nvavp_info *nvavp;
@@ -282,7 +299,7 @@ static void clock_disable_handler(struct work_struct *work)
mutex_lock(&channel_info->pushbuffer_lock);
mutex_lock(&nvavp->open_lock);
- if (nvavp_check_idle(nvavp) && nvavp->pending) {
+ if (nvavp_check_idle(nvavp, NVAVP_VIDEO_CHANNEL) && nvavp->pending) {
nvavp->pending = false;
nvavp_clks_disable(nvavp);
}
@@ -328,6 +345,13 @@ static int nvavp_service(struct nvavp_info *nvavp)
dev_err(&nvavp->nvhost_dev->dev, "AVP timeout\n");
writel(inbox & NVAVP_INBOX_VALID, NVAVP_OS_INBOX);
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (inbox & NVE276_OS_INTERRUPT_APP_NOTIFY) {
+ pr_debug("nvavp_service NVE276_OS_INTERRUPT_APP_NOTIFY\n");
+ schedule_work(&nvavp->app_notify_work);
+ }
+#endif
+
return 0;
}
@@ -970,18 +994,14 @@ static void nvavp_uninit(struct nvavp_info *nvavp)
if (video_initialized) {
pr_debug("nvavp_uninit nvavp->video_initialized\n");
cancel_work_sync(&nvavp->clock_disable_work);
-
nvavp_halt_vde(nvavp);
-
- clk_disable(nvavp->sclk);
- clk_disable(nvavp->emc_clk);
-
nvavp_set_video_init_status(nvavp, 0);
video_initialized = 0;
}
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
if (audio_initialized) {
+ cancel_work_sync(&nvavp->app_notify_work);
nvavp_set_audio_init_status(nvavp, 0);
audio_initialized = 0;
}
@@ -990,6 +1010,9 @@ static void nvavp_uninit(struct nvavp_info *nvavp)
/* Video and Audio both becomes uninitialized */
if (video_initialized == audio_initialized) {
pr_debug("nvavp_uninit both channels unitialized\n");
+
+ clk_disable(nvavp->sclk);
+ clk_disable(nvavp->emc_clk);
disable_irq(nvavp->mbox_from_avp_pend_irq);
nvavp_pushbuffer_deinit(nvavp);
nvavp_halt_avp(nvavp);
@@ -1250,6 +1273,62 @@ static int nvavp_force_clock_stay_on_ioctl(struct file *filp, unsigned int cmd,
return 0;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+static int nvavp_enable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct nvavp_clientctx *clientctx = filp->private_data;
+ struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_clock_args config;
+
+ if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args)))
+ return -EFAULT;
+
+ dev_dbg(&nvavp->nvhost_dev->dev, "%s: clk_id=%d\n",
+ __func__, config.id);
+
+ if (config.id == NVAVP_MODULE_ID_VCP)
+ clk_enable(nvavp->vcp_clk);
+ else if (config.id == NVAVP_MODULE_ID_BSEA)
+ clk_enable(nvavp->bsea_clk);
+
+ return 0;
+}
+
+static int nvavp_disable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct nvavp_clientctx *clientctx = filp->private_data;
+ struct nvavp_info *nvavp = clientctx->nvavp;
+ struct nvavp_clock_args config;
+
+ if (copy_from_user(&config, (void __user *)arg, sizeof(struct nvavp_clock_args)))
+ return -EFAULT;
+
+ dev_dbg(&nvavp->nvhost_dev->dev, "%s: clk_id=%d\n",
+ __func__, config.id);
+
+ if (config.id == NVAVP_MODULE_ID_VCP)
+ clk_disable(nvavp->vcp_clk);
+ else if (config.id == NVAVP_MODULE_ID_BSEA)
+ clk_disable(nvavp->bsea_clk);
+
+ return 0;
+}
+#else
+static int nvavp_enable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+
+static int nvavp_disable_audio_clocks(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+#endif
+
static int tegra_nvavp_open(struct inode *inode, struct file *filp, int channel_id)
{
struct miscdevice *miscdev = filp->private_data;
@@ -1367,6 +1446,12 @@ static long tegra_nvavp_ioctl(struct file *filp, unsigned int cmd,
case NVAVP_IOCTL_FORCE_CLOCK_STAY_ON:
ret = nvavp_force_clock_stay_on_ioctl(filp, cmd, arg);
break;
+ case NVAVP_IOCTL_ENABLE_AUDIO_CLOCKS:
+ ret = nvavp_enable_audio_clocks(filp, cmd, arg);
+ break;
+ case NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS:
+ ret = nvavp_disable_audio_clocks(filp, cmd, arg);
+ break;
default:
ret = -EINVAL;
break;
@@ -1540,6 +1625,22 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
goto err_get_emc_clk;
}
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp->bsea_clk = clk_get(&ndev->dev, "bsea");
+ if (IS_ERR(nvavp->bsea_clk)) {
+ dev_err(&ndev->dev, "cannot get bsea clock\n");
+ ret = -ENOENT;
+ goto err_get_bsea_clk;
+ }
+
+ nvavp->vcp_clk = clk_get(&ndev->dev, "vcp");
+ if (IS_ERR(nvavp->vcp_clk)) {
+ dev_err(&ndev->dev, "cannot get vcp clock\n");
+ ret = -ENOENT;
+ goto err_get_vcp_clk;
+ }
+#endif
+
nvavp->clk_enabled = 0;
nvavp_halt_avp(nvavp);
@@ -1558,6 +1659,7 @@ static int tegra_nvavp_probe(struct nvhost_device *ndev,
}
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ INIT_WORK(&nvavp->app_notify_work, app_notify_handler);
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;
@@ -1591,6 +1693,12 @@ err_audio_misc_reg:
#endif
misc_deregister(&nvavp->video_misc_dev);
err_misc_reg:
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ clk_put(nvavp->vcp_clk);
+err_get_vcp_clk:
+ clk_put(nvavp->bsea_clk);
+err_get_bsea_clk:
+#endif
clk_put(nvavp->emc_clk);
err_get_emc_clk:
clk_put(nvavp->sclk);
@@ -1639,6 +1747,8 @@ static int tegra_nvavp_remove(struct nvhost_device *ndev)
#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
misc_deregister(&nvavp->audio_misc_dev);
+ clk_put(nvavp->vcp_clk);
+ clk_put(nvavp->bsea_clk);
#endif
clk_put(nvavp->bsev_clk);
clk_put(nvavp->vde_clk);
@@ -1662,14 +1772,22 @@ static int tegra_nvavp_suspend(struct nvhost_device *ndev, pm_message_t state)
mutex_lock(&nvavp->open_lock);
if (nvavp->refcount) {
- if (!nvavp->clk_enabled)
+ if (!nvavp->clk_enabled) {
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ if (nvavp_check_idle(nvavp, NVAVP_AUDIO_CHANNEL))
+ nvavp_uninit(nvavp);
+ else
+ ret = -EBUSY;
+#else
nvavp_uninit(nvavp);
- else
+#endif
+ }
+ else {
ret = -EBUSY;
+ }
}
mutex_unlock(&nvavp->open_lock);
-
return ret;
}
@@ -1679,9 +1797,12 @@ static int tegra_nvavp_resume(struct nvhost_device *ndev)
mutex_lock(&nvavp->open_lock);
- if (nvavp->refcount)
+ if (nvavp->refcount) {
nvavp_init(nvavp, NVAVP_VIDEO_CHANNEL);
-
+#if defined(CONFIG_TEGRA_NVAVP_AUDIO)
+ nvavp_init(nvavp, NVAVP_AUDIO_CHANNEL);
+#endif
+ }
mutex_unlock(&nvavp->open_lock);
return 0;
diff --git a/drivers/media/video/tegra/ov5650.c b/drivers/media/video/tegra/ov5650.c
index bac1d00c3bd0..7fae83c21fe2 100644
--- a/drivers/media/video/tegra/ov5650.c
+++ b/drivers/media/video/tegra/ov5650.c
@@ -639,6 +639,11 @@ static struct ov5650_reg mode_320x240[] = {
{0x380f, 0x38},
+ {0x3500, 0x00},
+ {0x3501, 0x13},
+ {0x3502, 0x80},
+ {0x350b, 0x7f},
+
{0x3815, 0x81},
{0x3824, 0x23},
{0x3825, 0x20},
diff --git a/drivers/media/video/tegra/ov9726.c b/drivers/media/video/tegra/ov9726.c
index 378d46fabedf..45d6c85f0925 100644
--- a/drivers/media/video/tegra/ov9726.c
+++ b/drivers/media/video/tegra/ov9726.c
@@ -38,6 +38,7 @@ struct ov9726_devinfo {
struct ov9726_power_rail power_rail;
atomic_t in_use;
__u32 mode;
+ struct ov9726_reg grphold_temp[10];
};
static struct ov9726_reg mode_1280x720[] = {
@@ -603,6 +604,46 @@ static int ov9726_set_gain(struct i2c_client *i2c_client, u16 gain)
return ret;
}
+static int ov9726_set_group_hold(struct ov9726_devinfo *dev,
+ struct ov9726_ae *ae)
+{
+#define OV9726_REG_PUSH8(p, a, v) \
+ do { \
+ (p)->addr = (a); \
+ (p)->val = (v); \
+ (p)++; \
+ } while (0)
+
+#define OV9726_REG_PUSH16(ptr, addr, val) do { \
+ OV9726_REG_PUSH8(ptr, (addr), (val) >> 8); \
+ OV9726_REG_PUSH8(ptr, (addr) + 1, (val) & 0xff); \
+ } while (0)
+
+ struct ov9726_reg *gptr = &dev->grphold_temp[0];
+
+ if (!ae->gain_enable &&
+ !ae->coarse_time_enable &&
+ !ae->frame_length_enable)
+ return 0;
+
+ OV9726_REG_PUSH8(gptr, 0x0104, 0x01);
+ if (ae->gain_enable)
+ OV9726_REG_PUSH16(gptr,
+ OV9726_REG_GAIN_HI, ae->gain);
+ if (ae->coarse_time_enable)
+ OV9726_REG_PUSH16(gptr,
+ OV9726_REG_COARSE_TIME_HI, ae->coarse_time);
+ if (ae->frame_length_enable) {
+ OV9726_REG_PUSH16(gptr,
+ OV9726_REG_FRAME_LENGTH_HI, ae->frame_length);
+ }
+ OV9726_REG_PUSH8(gptr, 0x0104, 0x00);
+ OV9726_REG_PUSH8(gptr, OV9726_TABLE_END, 0x00);
+
+ return ov9726_write_table(dev->i2c_client,
+ dev->grphold_temp, NULL, 0);
+}
+
static int ov9726_get_status(struct i2c_client *i2c_client, u8 *status)
{
int err;
@@ -681,19 +722,26 @@ ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
-
case OV9726_IOCTL_SET_FRAME_LENGTH:
err = ov9726_set_frame_length(i2c_client, (u32)arg);
break;
-
case OV9726_IOCTL_SET_COARSE_TIME:
err = ov9726_set_coarse_time(i2c_client, (u32)arg);
break;
-
case OV9726_IOCTL_SET_GAIN:
err = ov9726_set_gain(i2c_client, (u16)arg);
break;
-
+ case OV9726_IOCTL_SET_GROUP_HOLD:
+ {
+ struct ov9726_ae ae;
+ if (copy_from_user(&ae,
+ (const void __user *)arg, sizeof(struct ov9726_ae))) {
+ pr_info("%s %d\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ err = ov9726_set_group_hold(dev, &ae);
+ break;
+ }
case OV9726_IOCTL_GET_STATUS:
{
u8 status;
@@ -706,7 +754,6 @@ ov9726_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
break;
}
-
default:
err = -EINVAL;
break;
diff --git a/drivers/media/video/tegra/sh532u.c b/drivers/media/video/tegra/sh532u.c
index 84692d992154..e41dd1f4afb1 100644
--- a/drivers/media/video/tegra/sh532u.c
+++ b/drivers/media/video/tegra/sh532u.c
@@ -1406,9 +1406,9 @@ 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)) {
+ sizeof(struct nv_focuser_config))) {
dev_err(&info->i2c_client->dev, "%s Error: copy_from_user bytes %d\n",
- __func__, params->sizeofvalue);
+ __func__, sizeof(struct nv_focuser_config));
return -EFAULT;
}
@@ -1420,7 +1420,7 @@ static int sh532u_set_focuser_capabilities(struct sh532u_info *info,
info->config.slew_rate = info->config.slew_rate;
dev_dbg(&info->i2c_client->dev, "%s: copy_from_user bytes %d\n",
- __func__, params->sizeofvalue);
+ __func__, sizeof(struct nv_focuser_config));
return 0;
}
@@ -1491,7 +1491,7 @@ static int sh532u_param_rd(struct sh532u_info *info, unsigned long arg)
sh532u_get_focuser_capabilities(info);
data_ptr = &info->config;
- data_size = params.sizeofvalue;
+ data_size = sizeof(info->config);
break;
case NVC_PARAM_STS:
diff --git a/drivers/media/video/tegra/tegra_camera.c b/drivers/media/video/tegra/tegra_camera.c
index 03eecf464c48..2b0cd005096c 100644
--- a/drivers/media/video/tegra/tegra_camera.c
+++ b/drivers/media/video/tegra/tegra_camera.c
@@ -2,7 +2,7 @@
* drivers/media/video/tegra/tegra_camera.c
*
* Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2012 Nvidia Corp
+ * 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
@@ -58,6 +58,25 @@ struct tegra_camera_block {
bool is_enabled;
};
+/*
+ * Declare and define two static variables to provide hint to
+ * gr3d module
+ */
+static int tegra_camera_on;
+static struct tegra_camera_platform_data *pdata;
+
+int is_tegra_camera_on(void)
+{
+ if (pdata) {
+ if (pdata->limit_3d_emc_clk)
+ return tegra_camera_on;
+ else
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
static int tegra_camera_enable_clk(struct tegra_camera_dev *dev)
{
clk_enable(dev->vi_clk);
@@ -227,6 +246,7 @@ static int tegra_camera_power_on(struct tegra_camera_dev *dev)
__func__);
#endif
dev->power_on = 1;
+ tegra_camera_on = dev->power_on;
return ret;
}
@@ -255,6 +275,7 @@ static int tegra_camera_power_off(struct tegra_camera_dev *dev)
}
}
dev->power_on = 0;
+ tegra_camera_on = dev->power_on;
return ret;
}
@@ -425,6 +446,7 @@ static int tegra_camera_probe(struct platform_device *pdev)
mutex_unlock(&dev->tegra_camera_lock);
dev->dev = &pdev->dev;
+ pdata = pdev->dev.platform_data;
/* Get regulator pointer */
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f37d3ec02123..10dba0cbda97 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -270,6 +270,11 @@ config TWL6040_CORE
select MFD_CORE
default n
+config AIC3262_CODEC
+ bool
+ select MFD_CORE
+ default n
+
config MFD_STMPE
bool "Support STMicroelectronics STMPE"
depends on I2C=y && GENERIC_HARDIRQS
@@ -353,6 +358,19 @@ config PMIC_ADP5520
individual components like LCD backlight, LEDs, GPIOs and Kepad
under the corresponding menus.
+config MFD_MAX77665
+ bool "Maxim Semiconductor MAX77665 Companion PMIC Support"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Say yes here to support for Maxim Semiconductor MAX77665.
+ This is a Power Management IC with Flash, Fuel Gauge, Haptic,
+ MUIC controls on chip.
+ This driver provides common support for accessing the device;
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
config MFD_MAX8925
bool "Maxim Semiconductor MAX8925 PMIC Support"
depends on I2C=y && GENERIC_HARDIRQS
@@ -783,6 +801,18 @@ config MFD_PM8XXX_IRQ
config TPS65911_COMPARATOR
tristate
+config MFD_TPS65090
+ bool "TPS65090 Power Management chips"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the TPS65090 series of
+ Power Management chips.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config MFD_AAT2870_CORE
bool "Support for the AnalogicTech AAT2870"
select MFD_CORE
@@ -804,18 +834,6 @@ config MFD_TPS6591X
additional drivers must be enabled in order to use the
functionality of the device.
-config MFD_TPS65090
- bool "TPS65090 Power Management chips"
- depends on I2C && GENERIC_HARDIRQS
- select MFD_CORE
- select REGMAP_I2C
- help
- If you say yes here you get support for the TPS65090 series of
- Power Management chips.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
-
config MFD_RC5T583
bool "Ricoh RC5T583 Power Management system device"
depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 6634515b64e4..c8dc50450219 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o
+obj-$(CONFIG_AIC3262_CODEC) += tlv320aic3262-core.o tlv320aic3262-irq.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
@@ -67,6 +68,7 @@ endif
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
obj-$(CONFIG_PMIC_DA903X) += da903x.o
+obj-$(CONFIG_MFD_MAX77665) += max77665.o
max8925-objs := max8925-core.o max8925-i2c.o
obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
@@ -101,9 +103,9 @@ obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
+obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_TPS6591X) += tps6591x.o
-obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_GPADC_TPS80031) += tps8003x-gpadc.o
obj-$(CONFIG_MFD_MAX8907C) += max8907c.o
diff --git a/drivers/mfd/max77665.c b/drivers/mfd/max77665.c
new file mode 100644
index 000000000000..b66712ba5737
--- /dev/null
+++ b/drivers/mfd/max77665.c
@@ -0,0 +1,371 @@
+/*
+ * Core driver for MAXIM MAX77665
+ *
+ * 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/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77665.h>
+#include <linux/slab.h>
+
+#define MAX77665_INT_STS 0x22
+#define MAX77665_INT_MSK 0x23
+#define MAX77665_PMIC_FLASH 0x00 ... 0x10
+#define MAX77665_PMIC_PMIC 0x20 ... 0x2D
+#define MAX77665_PMIC_CHARGER 0xB0 ... 0xC6
+#define MAX77665_MUIC 0x00 ... 0x0E
+#define MAX77665_HAPTIC 0x00 ... 0x10
+
+static u8 max77665_i2c_slave_address[] = {
+ [MAX77665_I2C_SLAVE_PMIC] = 0x66,
+ [MAX77665_I2C_SLAVE_MUIC] = 0x25,
+ [MAX77665_I2C_SLAVE_HAPTIC] = 0x48,
+};
+
+struct max77665_irq_data {
+ int bit;
+};
+
+#define MAX77665_IRQ(_id, _bit_pos) \
+ [MAX77665_IRQ_##_id] = { \
+ .bit = (_bit_pos), \
+ }
+
+static const struct max77665_irq_data max77665_irqs[] = {
+ MAX77665_IRQ(CHARGER, 0),
+ MAX77665_IRQ(TOP_SYS, 1),
+ MAX77665_IRQ(FLASH, 2),
+ MAX77665_IRQ(MUIC, 3),
+};
+
+static struct mfd_cell max77665s[] = {
+ {.name = "max77665-charger",},
+ {.name = "max77665-flash",},
+ {.name = "max77665-muic",},
+ {.name = "max77665-haptic",},
+};
+
+static void max77665_irq_lock(struct irq_data *data)
+{
+ struct max77665 *max77665 = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&max77665->irq_lock);
+}
+
+static void max77665_irq_mask(struct irq_data *irq_data)
+{
+ struct max77665 *max77665 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - max77665->irq_base;
+ const struct max77665_irq_data *data = &max77665_irqs[__irq];
+ int ret;
+
+ ret = max77665_set_bits(max77665->dev, MAX77665_I2C_SLAVE_PMIC,
+ MAX77665_INT_MSK, data->bit);
+ if (ret < 0)
+ dev_err(max77665->dev,
+ "Clearing mask reg failed e = %d\n", ret);
+}
+
+static void max77665_irq_unmask(struct irq_data *irq_data)
+{
+ struct max77665 *max77665 = irq_data_get_irq_chip_data(irq_data);
+ unsigned int __irq = irq_data->irq - max77665->irq_base;
+ const struct max77665_irq_data *data = &max77665_irqs[__irq];
+ int ret;
+
+ ret = max77665_clr_bits(max77665->dev, MAX77665_I2C_SLAVE_PMIC,
+ MAX77665_INT_MSK, data->bit);
+ if (ret < 0)
+ dev_err(max77665->dev,
+ "Setting mask reg failed e = %d\n", ret);
+}
+
+static void max77665_irq_sync_unlock(struct irq_data *data)
+{
+ struct max77665 *max77665 = irq_data_get_irq_chip_data(data);
+
+ mutex_unlock(&max77665->irq_lock);
+}
+
+static irqreturn_t max77665_irq(int irq, void *data)
+{
+ struct max77665 *max77665 = data;
+ int ret = 0;
+ u8 status = 0;
+ unsigned long int acks = 0;
+ int i;
+
+ ret = max77665_read(max77665->dev, MAX77665_I2C_SLAVE_PMIC,
+ MAX77665_INT_STS, &status);
+ if (ret < 0) {
+ dev_err(max77665->dev,
+ "failed to read status regi, e %d\n", ret);
+ return IRQ_NONE;
+ }
+ acks = status;
+ for_each_set_bit(i, &acks, ARRAY_SIZE(max77665_irqs))
+ handle_nested_irq(max77665->irq_base + i);
+ return acks ? IRQ_HANDLED : IRQ_NONE;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int max77665_irq_set_wake(struct irq_data *data, unsigned int enable)
+{
+ struct max77665 *max77665 = irq_data_get_irq_chip_data(data);
+
+ return irq_set_irq_wake(max77665->irq_base, enable);
+}
+
+#else
+#define max77665_irq_set_wake NULL
+#endif
+
+static int __devinit max77665_irq_init(struct max77665 *max77665, int irq,
+ int irq_base)
+{
+ int i, ret;
+
+ if (irq_base <= 0) {
+ dev_err(max77665->dev, "IRQ base not set, int not supported\n");
+ return -EINVAL;
+ }
+
+ mutex_init(&max77665->irq_lock);
+
+ ret = max77665_write(max77665->dev, MAX77665_I2C_SLAVE_PMIC,
+ MAX77665_INT_MSK, 0xFF);
+ if (ret < 0) {
+ dev_err(max77665->dev,
+ "Int mask reg write failed, e %d\n", ret);
+ return ret;
+ }
+
+ max77665->irq_base = irq_base;
+ max77665->irq_chip.name = "max77665";
+ max77665->irq_chip.irq_mask = max77665_irq_mask;
+ max77665->irq_chip.irq_unmask = max77665_irq_unmask;
+ max77665->irq_chip.irq_bus_lock = max77665_irq_lock;
+ max77665->irq_chip.irq_bus_sync_unlock = max77665_irq_sync_unlock;
+ max77665->irq_chip.irq_set_wake = max77665_irq_set_wake;
+
+ for (i = 0; i < ARRAY_SIZE(max77665_irqs); i++) {
+ int __irq = i + max77665->irq_base;
+ irq_set_chip_data(__irq, max77665);
+ irq_set_chip_and_handler(__irq, &max77665->irq_chip,
+ handle_simple_irq);
+ irq_set_nested_thread(__irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(__irq, IRQF_VALID);
+#endif
+ }
+
+ ret = request_threaded_irq(irq, NULL, max77665_irq, IRQF_ONESHOT,
+ "max77665", max77665);
+ if (ret < 0) {
+ dev_err(max77665->dev, "Int registration failed, e %d\n", ret);
+ return ret;
+ }
+
+ device_init_wakeup(max77665->dev, 1);
+ return ret;
+}
+
+static bool rd_wr_reg_pmic(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX77665_PMIC_FLASH:
+ case MAX77665_PMIC_PMIC:
+ case MAX77665_PMIC_CHARGER:
+ return true;
+ default:
+ dev_err(dev, "non-existing reg %s() reg 0x%x\n", __func__, reg);
+ return false;
+ }
+}
+
+static bool rd_wr_reg_muic(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX77665_MUIC:
+ return true;
+ default:
+ dev_err(dev, "non-existing reg %s() reg 0x%x\n", __func__, reg);
+ return false;
+ }
+}
+
+static bool rd_wr_reg_haptic(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MAX77665_HAPTIC:
+ return true;
+ default:
+ dev_err(dev, "non-existing reg %s() reg 0x%x\n", __func__, reg);
+ return false;
+ }
+}
+
+static const struct regmap_config max77665_regmap_config[] = {
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xFF,
+ .writeable_reg = rd_wr_reg_pmic,
+ .readable_reg = rd_wr_reg_pmic,
+ .cache_type = REGCACHE_RBTREE,
+ }, {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x0E,
+ .writeable_reg = rd_wr_reg_muic,
+ .readable_reg = rd_wr_reg_muic,
+ .cache_type = REGCACHE_RBTREE,
+ }, {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x10,
+ .writeable_reg = rd_wr_reg_haptic,
+ .readable_reg = rd_wr_reg_haptic,
+ .cache_type = REGCACHE_RBTREE,
+ },
+};
+
+static int __devinit max77665_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max77665_platform_data *pdata = client->dev.platform_data;
+ struct max77665 *max77665;
+ struct i2c_client *slv_client;
+ int ret;
+ int i;
+
+ if (!pdata) {
+ dev_err(&client->dev, "max77665 requires platform data\n");
+ return -EINVAL;
+ }
+
+ max77665 = devm_kzalloc(&client->dev, sizeof(*max77665), GFP_KERNEL);
+ if (!max77665) {
+ dev_err(&client->dev, "mem alloc for max77665 failed\n");
+ return -ENOMEM;
+ }
+
+ max77665->dev = &client->dev;
+
+ for (i = 0; i < MAX77665_I2C_SLAVE_MAX; ++i) {
+ slv_client = max77665->client[i];
+ if (i == 0)
+ slv_client = client;
+ else
+ slv_client = i2c_new_dummy(client->adapter,
+ max77665_i2c_slave_address[i]);
+ if (!slv_client) {
+ dev_err(&client->dev, "can't attach client %d\n", i);
+ ret = -ENOMEM;
+ goto err_exit;
+ }
+ i2c_set_clientdata(slv_client, max77665);
+
+ max77665->regmap[i] = devm_regmap_init_i2c(slv_client,
+ &max77665_regmap_config[i]);
+ if (IS_ERR(max77665->regmap[i])) {
+ ret = PTR_ERR(max77665->regmap[i]);
+ dev_err(&client->dev,
+ "regmap %d init failed with err: %d\n", i, ret);
+ goto err_exit;
+ }
+ }
+
+ if (client->irq > 0)
+ max77665_irq_init(max77665, client->irq, pdata->irq_base);
+
+ ret = mfd_add_devices(max77665->dev, -1, max77665s,
+ ARRAY_SIZE(max77665s), NULL, 0);
+ if (ret) {
+ dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+ ret);
+ goto err_irq_exit;
+ }
+
+ return 0;
+
+err_irq_exit:
+ if (client->irq > 0)
+ free_irq(client->irq, max77665);
+err_exit:
+ for (i = 0; i < MAX77665_I2C_SLAVE_MAX; ++i) {
+ slv_client = max77665->client[i];
+ if (slv_client && slv_client != client)
+ i2c_unregister_device(slv_client);
+ }
+ return ret;
+}
+
+static int __devexit max77665_i2c_remove(struct i2c_client *client)
+{
+ struct max77665 *max77665 = i2c_get_clientdata(client);
+ int i;
+ struct i2c_client *slv_client;
+
+ mfd_remove_devices(max77665->dev);
+ if (client->irq > 0)
+ free_irq(client->irq, max77665);
+
+ for (i = 0; i < MAX77665_I2C_SLAVE_MAX; ++i) {
+ slv_client = max77665->client[i];
+ if (slv_client && slv_client != client)
+ i2c_unregister_device(slv_client);
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id max77665_id_table[] = {
+ { "max77665", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, max77665_id_table);
+
+static struct i2c_driver max77665_driver = {
+ .driver = {
+ .name = "max77665",
+ .owner = THIS_MODULE,
+ },
+ .probe = max77665_i2c_probe,
+ .remove = __devexit_p(max77665_i2c_remove),
+ .id_table = max77665_id_table,
+};
+
+static int __init max77665_init(void)
+{
+ return i2c_add_driver(&max77665_driver);
+}
+subsys_initcall(max77665_init);
+
+static void __exit max77665_exit(void)
+{
+ i2c_del_driver(&max77665_driver);
+}
+module_exit(max77665_exit);
+
+MODULE_DESCRIPTION("MAXIM MAX77665 core driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tlv320aic3262-core.c b/drivers/mfd/tlv320aic3262-core.c
new file mode 100644
index 000000000000..7b61c7497a45
--- /dev/null
+++ b/drivers/mfd/tlv320aic3262-core.c
@@ -0,0 +1,885 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+#include <linux/gpio.h>
+
+#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#define DEBUG
+struct aic3262_gpio {
+ unsigned int reg;
+ u8 mask;
+ u8 shift;
+};
+struct aic3262_gpio aic3262_gpio_control[] = {
+ {
+ .reg = AIC3262_GPIO1_IO_CNTL,
+ .mask = AIC3262_GPIO_D6_D2,
+ .shift = AIC3262_GPIO_D2_SHIFT,
+ },
+ {
+ .reg = AIC3262_GPIO2_IO_CNTL,
+ .mask = AIC3262_GPIO_D6_D2,
+ .shift = AIC3262_GPIO_D2_SHIFT,
+ },
+ {
+ .reg = AIC3262_GPI1_EN,
+ .mask = AIC3262_GPI1_D2_D1,
+ .shift = AIC3262_GPIO_D1_SHIFT,
+ },
+ {
+ .reg = AIC3262_GPI2_EN,
+ .mask = AIC3262_GPI2_D5_D4,
+ .shift = AIC3262_GPIO_D4_SHIFT,
+ },
+ {
+ .reg = AIC3262_GPO1_OUT_CNTL,
+ .mask = AIC3262_GPO1_D4_D1,
+ .shift = AIC3262_GPIO_D1_SHIFT,
+ },
+};
+static int aic3262_read(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, void *dest)
+{
+ int ret;
+ int i;
+ u8 *buf = dest;
+
+ BUG_ON(bytes <= 0);
+
+ ret = aic3262->read_dev(aic3262, reg, bytes, dest);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < bytes ; i++) {
+ dev_vdbg(aic3262->dev, "Read %04x from R%d(0x%x)\n",
+ buf[i], reg + i, reg + i);
+ }
+
+ return ret;
+}
+
+/**
+ * aic3262_reg_read: Read a single TLV320AIC3262 register.
+ *
+ * @aic3262: Device to read from.
+ * @reg: Register to read.
+ */
+int aic3262_reg_read(struct aic3262 *aic3262, unsigned int reg)
+{
+ unsigned char val;
+ int ret;
+
+ mutex_lock(&aic3262->io_lock);
+
+ ret = aic3262_read(aic3262, reg, 1, &val);
+
+ mutex_unlock(&aic3262->io_lock);
+
+ if (ret < 0)
+ return ret;
+ else
+ return val;
+}
+EXPORT_SYMBOL_GPL(aic3262_reg_read);
+
+/**
+ * aic3262_bulk_read: Read multiple TLV320AIC3262 registers
+ *
+ * @aic3262: Device to read from
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to fill. The data will be returned big endian.
+ */
+int aic3262_bulk_read(struct aic3262 *aic3262, unsigned int reg,
+ int count, u8 *buf)
+{
+ int ret;
+
+ mutex_lock(&aic3262->io_lock);
+
+ ret = aic3262_read(aic3262, reg, count, buf);
+
+ mutex_unlock(&aic3262->io_lock);
+
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_bulk_read);
+
+static int aic3262_write(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, const void *src)
+{
+ const u8 *buf = src;
+ int i;
+
+ BUG_ON(bytes <= 0);
+
+ for (i = 0; i < bytes ; i++) {
+ dev_vdbg(aic3262->dev, "Write %04x to R%d(0x%x)\n",
+ buf[i], reg + i, reg + i);
+ }
+
+ return aic3262->write_dev(aic3262, reg, bytes, src);
+}
+
+/**
+ * aic3262_reg_write: Write a single TLV320AIC3262 register.
+ *
+ * @aic3262: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ */
+int aic3262_reg_write(struct aic3262 *aic3262, unsigned int reg,
+ unsigned char val)
+{
+ int ret;
+
+
+ mutex_lock(&aic3262->io_lock);
+
+ dev_dbg(aic3262->dev, "w 30 %x %x", reg, val);
+ ret = aic3262_write(aic3262, reg, 1, &val);
+
+ mutex_unlock(&aic3262->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_reg_write);
+
+/**
+ * aic3262_bulk_write: Write multiple TLV320AIC3262 registers
+ *
+ * @aic3262: Device to write to
+ * @reg: First register
+ * @count: Number of registers
+ * @buf: Buffer to write from. Data must be big-endian formatted.
+ */
+int aic3262_bulk_write(struct aic3262 *aic3262, unsigned int reg,
+ int count, const u8 *buf)
+{
+ int ret;
+
+ mutex_lock(&aic3262->io_lock);
+
+ ret = aic3262_write(aic3262, reg, count, buf);
+
+ mutex_unlock(&aic3262->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_bulk_write);
+
+/**
+ * aic3262_set_bits: Set the value of a bitfield in a TLV320AIC3262 register
+ *
+ * @aic3262: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ */
+int aic3262_set_bits(struct aic3262 *aic3262, unsigned int reg,
+ unsigned char mask, unsigned char val)
+{
+ int ret;
+ u8 r;
+
+ mutex_lock(&aic3262->io_lock);
+
+ ret = aic3262_read(aic3262, reg, 1, &r);
+ if (ret < 0)
+ goto out;
+
+
+ r &= ~mask;
+ r |= (val & mask);
+
+ dev_dbg(aic3262->dev, "w 30 %x %x", reg, r);
+ ret = aic3262_write(aic3262, reg, 1, &r);
+
+out:
+ mutex_unlock(&aic3262->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(aic3262_set_bits);
+
+/**
+ * aic3262_wait_bits: wait for a value of a bitfield in a TLV320AIC3262 register
+ *
+ * @aic3262: Device to write to.
+ * @reg: Register to write to.
+ * @mask: Mask of bits to set.
+ * @val: Value to set (unshifted)
+ * @sleep: mdelay value in each iteration in milliseconds
+ * @count: iteration count for timeout
+ */
+int aic3262_wait_bits(struct aic3262 *aic3262, unsigned int reg,
+ unsigned char mask, unsigned char val, int sleep, int counter)
+{
+ int status;
+ int timeout = sleep*counter;
+
+ status = aic3262_reg_read(aic3262, reg);
+ while (((status & mask) != val) && counter) {
+ mdelay(sleep);
+ status = aic3262_reg_read(aic3262, reg);
+ counter--;
+ };
+ if (!counter)
+ dev_err(aic3262->dev,
+ "wait_bits timedout (%d millisecs). lastval 0x%x\n",
+ timeout, status);
+ return counter;
+}
+EXPORT_SYMBOL_GPL(aic3262_wait_bits);
+
+/* to be changed -- Mukund*/
+static struct resource aic3262_codec_resources[] = {
+ {
+ .start = AIC3262_IRQ_HEADSET_DETECT,
+ .end = AIC3262_IRQ_SPEAKER_OVER_TEMP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource aic3262_gpio_resources[] = {
+ {
+ .start = AIC3262_GPIO1,
+ .end = AIC3262_GPO1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell aic3262_devs[] = {
+ {
+ .name = "tlv320aic3262-codec",
+ .num_resources = ARRAY_SIZE(aic3262_codec_resources),
+ .resources = aic3262_codec_resources,
+ },
+
+ {
+ .name = "tlv320aic3262-gpio",
+ .num_resources = ARRAY_SIZE(aic3262_gpio_resources),
+ .resources = aic3262_gpio_resources,
+ .pm_runtime_no_callbacks = true,
+ },
+};
+
+
+#ifdef CONFIG_PM
+static int aic3262_suspend(struct device *dev)
+{
+ struct aic3262 *aic3262 = dev_get_drvdata(dev);
+
+ aic3262->suspended = true;
+
+ return 0;
+}
+
+static int aic3262_resume(struct device *dev)
+{
+ struct aic3262 *aic3262 = dev_get_drvdata(dev);
+
+
+ aic3262->suspended = false;
+
+ return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(aic3262_pm_ops, aic3262_suspend, aic3262_resume,
+ NULL);
+#endif
+
+
+/*
+ * Instantiate the generic non-control parts of the device.
+ */
+static int aic3262_device_init(struct aic3262 *aic3262, int irq)
+{
+ struct aic3262_pdata *pdata = aic3262->dev->platform_data;
+ const char *devname;
+ int ret, i;
+ u8 revID, pgID;
+ unsigned int naudint = 0;
+ u8 resetVal = 1;
+
+ mutex_init(&aic3262->io_lock);
+ dev_set_drvdata(aic3262->dev, aic3262);
+ if (pdata) {
+ if (pdata->gpio_reset) {
+ ret = gpio_request(pdata->gpio_reset,
+ "aic3262-reset-pin");
+ if (ret != 0) {
+ dev_err(aic3262->dev,
+ "Failed to reset aic3262 using gpio %d\n",
+ pdata->gpio_reset);
+ goto err_return;
+ }
+ gpio_direction_output(pdata->gpio_reset, 1);
+ mdelay(5);
+ gpio_direction_output(pdata->gpio_reset, 0);
+ mdelay(5);
+ gpio_direction_output(pdata->gpio_reset, 1);
+ mdelay(5);
+ }
+ }
+
+
+ /* run the codec through software reset */
+ ret = aic3262_reg_write(aic3262, AIC3262_RESET_REG, resetVal);
+ if (ret < 0) {
+ dev_err(aic3262->dev, "Could not write to AIC3262 register\n");
+ goto err_return;
+ }
+
+ mdelay(10);
+
+ ret = aic3262_reg_read(aic3262, AIC3262_REV_PG_ID);
+ if (ret < 0) {
+ dev_err(aic3262->dev, "Failed to read ID register\n");
+ goto err_return;
+ }
+ revID = (ret & AIC3262_REV_MASK) >> AIC3262_REV_SHIFT;
+ pgID = (ret & AIC3262_PG_MASK) >> AIC3262_PG_SHIFT;
+ switch (revID) {
+ case 3:
+ devname = "TLV320AIC3262";
+ if (aic3262->type != TLV320AIC3262)
+ dev_warn(aic3262->dev, "Device registered as type %d\n",
+ aic3262->type);
+ aic3262->type = TLV320AIC3262;
+ break;
+ case 1:
+ devname = "TLV320AIC3262";
+ if (aic3262->type != TLV320AIC3262)
+ dev_warn(aic3262->dev, "Device registered as type %d\n",
+ aic3262->type);
+ aic3262->type = TLV320AIC3262;
+ break;
+
+ default:
+ dev_err(aic3262->dev, "Device is not a TLV320AIC3262, ID is %x\n",
+ ret);
+ ret = -EINVAL;
+ goto err_return;
+
+ }
+
+ dev_info(aic3262->dev, "%s revision %c\n", devname, 'D' + ret);
+
+
+ if (pdata) {
+ if (pdata->gpio_irq == 1) {
+ naudint = gpio_to_irq(pdata->naudint_irq);
+ gpio_request(pdata->naudint_irq, "aic3262-gpio-irq");
+ gpio_direction_input(pdata->naudint_irq);
+ } else
+ naudint = pdata->naudint_irq;
+
+ aic3262->irq = naudint;
+ aic3262->irq_base = pdata->irq_base;
+ for (i = 0; i < AIC3262_NUM_GPIO; i++) {
+ if (pdata->gpio[i].used) {
+ /* Direction is input */
+ if (pdata->gpio[i].in) {
+ /* set direction to input for GPIO,
+ and enable for GPI */
+ aic3262_set_bits(aic3262,
+ aic3262_gpio_control[i].reg,
+ aic3262_gpio_control[i].mask,
+ 0x1 <<
+ aic3262_gpio_control[i].shift);
+
+ if (pdata->gpio[i].in_reg)
+ /* Some input modes, does not
+ need extra registers to be
+ written */
+ aic3262_set_bits(aic3262,
+ pdata->gpio[i].in_reg,
+ pdata->gpio[i].
+ in_reg_bitmask,
+ pdata->gpio[i].value <<
+ pdata->gpio[i].
+ in_reg_shift);
+ } else {
+ /* Direction si output */
+ aic3262_set_bits(aic3262,
+ aic3262_gpio_control[i].reg,
+ aic3262_gpio_control[i].mask,
+ pdata->gpio[i].value <<
+ aic3262_gpio_control[i].shift);
+ }
+ } else
+ aic3262_set_bits(aic3262,
+ aic3262_gpio_control[i].reg,
+ aic3262_gpio_control[i].mask, 0x0);
+ }
+ }
+
+ if (naudint) {
+ /* codec interrupt */
+ ret = aic3262_irq_init(aic3262);
+ if (ret)
+ goto err_irq;
+ }
+
+ ret = mfd_add_devices(aic3262->dev, -1,
+ aic3262_devs, ARRAY_SIZE(aic3262_devs),
+ NULL, 0);
+ if (ret != 0) {
+ dev_err(aic3262->dev, "Failed to add children: %d\n", ret);
+ goto err_irq;
+ }
+
+ pm_runtime_enable(aic3262->dev);
+ pm_runtime_resume(aic3262->dev);
+
+ return 0;
+
+err_irq:
+ aic3262_irq_exit(aic3262);
+err_return:
+ kfree(aic3262);
+ return ret;
+}
+
+static void aic3262_device_exit(struct aic3262 *aic3262)
+{
+ pm_runtime_disable(aic3262->dev);
+ mfd_remove_devices(aic3262->dev);
+ aic3262_irq_exit(aic3262);
+ kfree(aic3262);
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+
+static int aic3262_i2c_read_device(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, void *dest)
+{
+ struct i2c_client *i2c = aic3262->control_data;
+ union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+ char *value;
+ int ret;
+ u8 buf[2];
+ u8 page, book, offset;
+ page = aic_reg->aic326x_register.page;
+ book = aic_reg->aic326x_register.book;
+ offset = aic_reg->aic326x_register.offset;
+ if (aic3262->book_no != book) {
+ /* We should change to page 0.
+ Change the book by writing to offset 127 of page 0
+ Change the page back to whatever was set before change page */
+ buf[0] = 0x0;
+ buf[1] = 0x0;
+ ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+ buf[0] = 127;
+ buf[1] = book;
+ ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+ aic3262->book_no = book;
+ aic3262->page_no = 0x0;
+ }
+
+ if (aic3262->page_no != page) {
+ buf[0] = 0x0;
+ buf[1] = page;
+ ret = i2c_master_send(i2c, (unsigned char *) buf, 2);
+
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+ aic3262->page_no = page;
+ }
+
+ /* Send the required offset */
+ buf[0] = offset ;
+ ret = i2c_master_send(i2c, (unsigned char *)buf, 1);
+ if (ret < 0)
+ return ret;
+ if (ret != 1)
+ return -EIO;
+
+ ret = i2c_master_recv(i2c, dest, bytes);
+ value = dest;
+ if (ret < 0)
+ return ret;
+ if (ret != bytes)
+ return -EIO;
+ return ret;
+}
+
+static int aic3262_i2c_write_device(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, const void *src)
+{
+ struct i2c_client *i2c = aic3262->control_data;
+ int ret;
+
+ union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+
+ u8 buf[2];
+ u8 write_buf[bytes + 1];
+ u8 page, book, offset;
+ page = aic_reg->aic326x_register.page;
+ book = aic_reg->aic326x_register.book;
+ offset = aic_reg->aic326x_register.offset;
+ if (aic3262->book_no != book) {
+ /* We should change to page 0.
+ Change the book by writing to offset 127 of page 0
+ Change the page back to whatever was set before change page*/
+ buf[0] = 0x0;
+ buf[1] = 0x0;
+ ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+ buf[0] = 127;
+ buf[1] = book;
+ ret = i2c_master_send(i2c, (unsigned char *)buf, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+ aic3262->book_no = book;
+ aic3262->page_no = 0x0;
+ }
+
+ if (aic3262->page_no != page) {
+ buf[0] = 0x0;
+ buf[1] = page;
+ ret = i2c_master_send(i2c, (unsigned char *) buf, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+ aic3262->page_no = page;
+ }
+ write_buf[0] = offset;
+ memcpy(&write_buf[1], src, bytes);
+ ret = i2c_master_send(i2c, write_buf, bytes + 1);
+ if (ret < 0)
+ return ret;
+ if (ret != (bytes + 1))
+ return -EIO;
+
+ return 0;
+}
+
+static int aic3262_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct aic3262 *aic3262;
+
+ aic3262 = kzalloc(sizeof(struct aic3262), GFP_KERNEL);
+ if (aic3262 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, aic3262);
+ aic3262->dev = &i2c->dev;
+ aic3262->control_data = i2c;
+ aic3262->read_dev = aic3262_i2c_read_device;
+ aic3262->write_dev = aic3262_i2c_write_device;
+ aic3262->type = id->driver_data;
+ aic3262->book_no = 255;
+ aic3262->page_no = 255;
+
+ return aic3262_device_init(aic3262, i2c->irq);
+}
+
+static int aic3262_i2c_remove(struct i2c_client *i2c)
+{
+ struct aic3262 *aic3262 = i2c_get_clientdata(i2c);
+
+ aic3262_device_exit(aic3262);
+
+ return 0;
+}
+
+static const struct i2c_device_id aic3262_i2c_id[] = {
+ { "tlv320aic3262", TLV320AIC3262 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, aic3262_i2c_id);
+
+
+static struct i2c_driver aic3262_i2c_driver = {
+ .driver = {
+ .name = "tlv320aic3262",
+ .owner = THIS_MODULE,
+ .pm = &aic3262_pm_ops,
+ },
+ .probe = aic3262_i2c_probe,
+ .remove = aic3262_i2c_remove,
+ .id_table = aic3262_i2c_id,
+};
+
+static int __init aic3262_i2c_init(void)
+{
+ int ret;
+ ret = i2c_add_driver(&aic3262_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register aic3262 I2C driver: %d\n", ret);
+
+ return ret;
+}
+module_init(aic3262_i2c_init);
+
+static void __exit aic3262_i2c_exit(void)
+{
+ i2c_del_driver(&aic3262_i2c_driver);
+}
+module_exit(aic3262_i2c_exit);
+#endif
+#if defined(CONFIG_SPI_MASTER)
+/* TODO: UGLY
+ * NVidia's CS differs from what TI requires on the SPI bus. So before
+ * we do any write/read we pull down the CS gpio :(
+ * The problem is in spi_read.
+ * Can we set the flag spi_transfer.cs_change during read so that CS is
+ * pulled low until the next transaction occurs
+ * (spi_read requires a spi_write followed by spi_read)
+ */
+#include <linux/gpio.h>
+#include "../../../arch/arm/mach-tegra/gpio-names.h"
+#include <linux/delay.h>
+#define SPI_CS TEGRA_GPIO_PX3
+#define CS(a) gpio_set_value(SPI_CS, a)
+void nvidia_spi_cs_en(bool stop)
+{
+ if (stop) {
+ CS(1);
+ udelay(1);
+ } else {
+ CS(0);
+ udelay(1);
+ }
+ return;
+}
+static int aic3262_spi_read_device(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, void *dest)
+{
+ struct spi_device *spi = aic3262->control_data;
+ union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+ u8 *write_read_buf;
+ unsigned int i;
+ unsigned int time;
+ unsigned int last_count;
+ unsigned int spi_read_bufsize = max(32, SMP_CACHE_BYTES)-1;
+ struct spi_message message;
+ struct spi_transfer x[2];
+ int ret;
+ u8 buf[2];
+ u8 page, book, offset;
+ page = aic_reg->aic326x_register.page;
+ book = aic_reg->aic326x_register.book;
+ offset = aic_reg->aic326x_register.offset;
+ if (aic3262->book_no != book) {
+ /* We should change to page 0.
+ Change the book by writing to offset 127 of page 0
+ Change the page back to whatever was set before change page */
+
+ buf[0] = 0x0;
+ buf[1] = 0x0;
+
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, (unsigned char *)buf, 2);
+ nvidia_spi_cs_en(1);
+
+ if (ret < 0)
+ return ret;
+ buf[0] = (127 << 1) ;
+ buf[1] = book;
+
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, (unsigned char *)buf, 2);
+ nvidia_spi_cs_en(1);
+
+ if (ret < 0)
+ return ret;
+ aic3262->book_no = book;
+ aic3262->page_no = 0x0;
+ }
+
+ if (aic3262->page_no != page) {
+ buf[0] = 0x0;
+ buf[1] = page;
+
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, (unsigned char *)buf, 2);
+ nvidia_spi_cs_en(1);
+
+ if (ret < 0)
+ return ret;
+ aic3262->page_no = page;
+ }
+
+ buf[0] = (offset << 1) | (0x01) ;
+ memset(x, 0, sizeof x);
+ spi_message_init(&message);
+ x[0].len = 1;
+ x[0].tx_buf = buf;
+ x[1].len = bytes;
+ x[1].rx_buf = dest ;
+
+ spi_message_add_tail(&x[0], &message);
+ spi_message_add_tail(&x[1], &message);
+
+ nvidia_spi_cs_en(0);
+ ret = spi_sync(spi, &message);
+ nvidia_spi_cs_en(1);
+ if (ret < 0)
+ return ret;
+
+ return bytes;
+
+}
+/* NVidia's CS differs from what TI requires on the SPI bus. So before
+ * we do any write/read we pull down the CS gpio :(
+ */
+static int aic3262_spi_write_device(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, const void *src)
+{
+ struct spi_device *spi = aic3262->control_data;
+ int ret;
+
+ union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+
+ u8 buf[2];
+ u8 write_buf[bytes + 1];
+ u8 page, book, offset;
+ page = aic_reg->aic326x_register.page;
+ book = aic_reg->aic326x_register.book;
+ offset = aic_reg->aic326x_register.offset;
+ if (aic3262->book_no != book) {
+ /* We should change to page 0.
+ Change the book by writing to offset 127 of page 0
+ Change the page back to whatever was set before change page */
+
+ buf[0] = 0x0;
+ buf[1] = 0x0;
+
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, (unsigned char *)buf, 2);
+ nvidia_spi_cs_en(1);
+
+ if (ret < 0)
+ return ret;
+ buf[0] = (127 << 1) ;
+ buf[1] = book;
+
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, (unsigned char *)buf, 2);
+ nvidia_spi_cs_en(1);
+
+ if (ret < 0)
+ return ret;
+ aic3262->book_no = book;
+ aic3262->page_no = 0x0;
+ }
+
+ if (aic3262->page_no != page) {
+ buf[0] = 0x0;
+ buf[1] = page;
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, (unsigned char *) buf, 2);
+ nvidia_spi_cs_en(1);
+ if (ret < 0)
+ return ret;
+ aic3262->page_no = page;
+ }
+ write_buf[0] = offset << 1 ;
+ memcpy(&write_buf[1], src, bytes);
+ nvidia_spi_cs_en(0);
+ ret = spi_write(spi, write_buf, bytes + 1);
+ nvidia_spi_cs_en(1);
+ if (ret < 0)
+ return ret;
+
+ return bytes;
+}
+
+static int aic3262_spi_probe(struct spi_device *spi)
+{
+ struct aic3262 *aic3262;
+
+ aic3262 = kzalloc(sizeof(struct aic3262), GFP_KERNEL);
+ if (aic3262 == NULL)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, aic3262);
+ aic3262->dev = &spi->dev;
+ aic3262->control_data = spi;
+ aic3262->read_dev = aic3262_spi_read_device;
+ aic3262->write_dev = aic3262_spi_write_device;
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_1;
+ spi->max_speed_hz = 4000*1000;
+ spi_setup(spi);
+
+ if (strcmp(spi->modalias, "tlv320aic3262") == 0)
+ aic3262->type = TLV320AIC3262;
+ aic3262->book_no = 255;
+ aic3262->page_no = 255;
+
+ return aic3262_device_init(aic3262, spi->irq);
+}
+
+static int aic3262_spi_remove(struct spi_device *spi)
+{
+ struct aic3262 *aic3262 = spi_get_drvdata(spi);
+
+ aic3262_device_exit(aic3262);
+
+ return 0;
+}
+
+static struct spi_driver aic3262_spi_driver = {
+ .driver = {
+ .name = "tlv320aic3262",
+ .owner = THIS_MODULE,
+ .pm = &aic3262_pm_ops,
+ },
+ .probe = aic3262_spi_probe,
+ .remove = aic3262_spi_remove,
+};
+
+static int __init aic3262_spi_init(void)
+{
+ int ret;
+ ret = spi_register_driver(&aic3262_spi_driver);
+ if (ret != 0)
+ pr_err("Failed to register aic3262 SPI driver: %d\n", ret);
+
+ return ret;
+}
+module_init(aic3262_spi_init);
+
+static void __exit aic3262_spi_exit(void)
+{
+ spi_unregister_driver(&aic3262_spi_driver);
+}
+module_exit(aic3262_spi_exit);
+#endif
+
+MODULE_DESCRIPTION("Core support for the TLV320AIC3262 audio CODEC");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mukund Navada <navada@ti.com>");
diff --git a/drivers/mfd/tlv320aic3262-irq.c b/drivers/mfd/tlv320aic3262-irq.c
new file mode 100644
index 000000000000..7e7a5499f3e5
--- /dev/null
+++ b/drivers/mfd/tlv320aic3262-irq.c
@@ -0,0 +1,204 @@
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+
+#include <linux/delay.h>
+struct aic3262_irq_data {
+ int mask;
+ int status;
+};
+
+static struct aic3262_irq_data aic3262_irqs[] = {
+ {
+ .mask = AIC3262_HEADSET_IN_MASK,
+ .status = AIC3262_HEADSET_PLUG_UNPLUG_INT,
+ },
+ {
+ .mask = AIC3262_BUTTON_PRESS_MASK,
+ .status = AIC3262_BUTTON_PRESS_INT,
+ },
+ {
+ .mask = AIC3262_DAC_DRC_THRES_MASK,
+ .status = AIC3262_LEFT_DRC_THRES_INT | AIC3262_RIGHT_DRC_THRES_INT,
+ },
+ {
+ .mask = AIC3262_AGC_NOISE_MASK,
+ .status = AIC3262_LEFT_AGC_NOISE_INT | AIC3262_RIGHT_AGC_NOISE_INT,
+ },
+ {
+ .mask = AIC3262_OVER_CURRENT_MASK,
+ .status = AIC3262_LEFT_OUTPUT_DRIVER_OVERCURRENT_INT
+ | AIC3262_RIGHT_OUTPUT_DRIVER_OVERCURRENT_INT,
+ },
+ {
+ .mask = AIC3262_OVERFLOW_MASK,
+ .status =
+ AIC3262_LEFT_DAC_OVERFLOW_INT | AIC3262_RIGHT_DAC_OVERFLOW_INT |
+ AIC3262_MINIDSP_D_BARREL_SHIFT_OVERFLOW_INT |
+ AIC3262_LEFT_ADC_OVERFLOW_INT | AIC3262_RIGHT_ADC_OVERFLOW_INT |
+ AIC3262_MINIDSP_D_BARREL_SHIFT_OVERFLOW_INT,
+ },
+ {
+ .mask = AIC3262_SPK_OVERCURRENT_MASK,
+ .status = AIC3262_SPK_OVER_CURRENT_INT,
+ },
+
+};
+
+struct aic3262_gpio_data {
+
+};
+
+static inline struct aic3262_irq_data *irq_to_aic3262_irq(struct aic3262
+ *aic3262, int irq)
+{
+ return &aic3262_irqs[irq - aic3262->irq_base];
+}
+
+static void aic3262_irq_lock(struct irq_data *data)
+{
+ struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&aic3262->irq_lock);
+}
+
+static void aic3262_irq_sync_unlock(struct irq_data *data)
+{
+ struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+
+ /* write back to hardware any change in irq mask */
+ if (aic3262->irq_masks_cur != aic3262->irq_masks_cache) {
+ aic3262->irq_masks_cache = aic3262->irq_masks_cur;
+ aic3262_reg_write(aic3262, AIC3262_INT1_CNTL,
+ aic3262->irq_masks_cur);
+ }
+
+ mutex_unlock(&aic3262->irq_lock);
+}
+
+static void aic3262_irq_unmask(struct irq_data *data)
+{
+ struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+ struct aic3262_irq_data *irq_data =
+ irq_to_aic3262_irq(aic3262, data->irq);
+
+ aic3262->irq_masks_cur |= irq_data->mask;
+}
+
+static void aic3262_irq_mask(struct irq_data *data)
+{
+ struct aic3262 *aic3262 = irq_data_get_irq_chip_data(data);
+ struct aic3262_irq_data *irq_data =
+ irq_to_aic3262_irq(aic3262, data->irq);
+
+ aic3262->irq_masks_cur &= ~irq_data->mask;
+}
+
+static struct irq_chip aic3262_irq_chip = {
+ .name = "tlv320aic3262",
+ .irq_bus_lock = aic3262_irq_lock,
+ .irq_bus_sync_unlock = aic3262_irq_sync_unlock,
+ .irq_mask = aic3262_irq_mask,
+ .irq_unmask = aic3262_irq_unmask,
+};
+
+static irqreturn_t aic3262_irq_thread(int irq, void *data)
+{
+ struct aic3262 *aic3262 = data;
+ u8 status[4];
+ int i = 0;
+ /* Reading the sticky bit registers acknowledges
+ the interrupt to the device */
+ aic3262_bulk_read(aic3262, AIC3262_INT_STICKY_FLAG1, 4, status);
+
+ /* report */
+ if (status[2] & aic3262_irqs[AIC3262_IRQ_HEADSET_DETECT].status)
+ handle_nested_irq(aic3262->irq_base);
+
+ if (status[2] & aic3262_irqs[AIC3262_IRQ_BUTTON_PRESS].status)
+ handle_nested_irq(aic3262->irq_base + 1);
+ if (status[2] & aic3262_irqs[AIC3262_IRQ_DAC_DRC].status)
+ handle_nested_irq(aic3262->irq_base + 2);
+ if (status[3] & aic3262_irqs[AIC3262_IRQ_AGC_NOISE].status)
+ handle_nested_irq(aic3262->irq_base + 3);
+ if (status[2] & aic3262_irqs[AIC3262_IRQ_OVER_CURRENT].status)
+ handle_nested_irq(aic3262->irq_base + 4);
+ if (status[0] & aic3262_irqs[AIC3262_IRQ_OVERFLOW_EVENT].status)
+ handle_nested_irq(aic3262->irq_base + 5);
+ if (status[3] & aic3262_irqs[AIC3262_IRQ_SPEAKER_OVER_TEMP].status)
+ handle_nested_irq(aic3262->irq_base + 6);
+
+ /* ack unmasked irqs */
+ /* No need to acknowledge the interrupt on AIC3262 */
+
+ return IRQ_HANDLED;
+}
+
+int aic3262_irq_init(struct aic3262 *aic3262)
+{
+ int cur_irq, ret;
+
+ mutex_init(&aic3262->irq_lock);
+
+ /* mask the individual interrupt sources */
+ aic3262->irq_masks_cur = 0x0;
+ aic3262->irq_masks_cache = 0x0;
+ aic3262_reg_write(aic3262, AIC3262_INT1_CNTL, 0x0);
+
+ if (!aic3262->irq) {
+ dev_warn(aic3262->dev,
+ "no interrupt specified, no interrupts\n");
+ aic3262->irq_base = 0;
+ return 0;
+ }
+
+ if (!aic3262->irq_base) {
+ dev_err(aic3262->dev,
+ "no interrupt base specified, no interrupts\n");
+ return 0;
+ }
+
+ /* Register them with genirq */
+ for (cur_irq = aic3262->irq_base;
+ cur_irq < aic3262->irq_base + ARRAY_SIZE(aic3262_irqs);
+ cur_irq++) {
+ irq_set_chip_data(cur_irq, aic3262);
+ irq_set_chip_and_handler(cur_irq, &aic3262_irq_chip,
+ handle_edge_irq);
+ irq_set_nested_thread(cur_irq, 1);
+
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ set_irq_noprobe(cur_irq);
+#endif
+ }
+
+ ret = request_threaded_irq(aic3262->irq, NULL, aic3262_irq_thread,
+ IRQF_TRIGGER_RISING,
+ "tlv320aic3262", aic3262);
+ if (ret) {
+ dev_err(aic3262->dev, "failed to request IRQ %d: %d\n",
+ aic3262->irq, ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(aic3262_irq_init);
+
+void aic3262_irq_exit(struct aic3262 *aic3262)
+{
+ if (aic3262->irq)
+ free_irq(aic3262->irq, aic3262);
+}
+EXPORT_SYMBOL(aic3262_irq_exit);
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
index 080f97aa264b..25f463de1513 100644
--- a/drivers/mfd/tps65090.c
+++ b/drivers/mfd/tps65090.c
@@ -1,37 +1,33 @@
/*
- * driver/mfd/tps65090.c
- *
* Core driver for TI TPS65090 PMIC family
*
- * 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
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-
#include <linux/mfd/core.h>
#include <linux/mfd/tps65090.h>
-#include <linux/regmap.h>
+#include <linux/err.h>
+
+#define NUM_INT_REG 2
+#define TOTAL_NUM_REG 0x18
/* interrupt status registers */
#define TPS65090_INT_STS 0x0
@@ -41,95 +37,41 @@
#define TPS65090_INT_MSK 0x2
#define TPS65090_INT_MSK2 0x3
-
-enum irq_type {
- EVENT,
-};
-
struct tps65090_irq_data {
u8 mask_reg;
u8 mask_pos;
- enum irq_type type;
};
-#define TPS65090_IRQ(_reg, _mask_pos, _type) \
+#define TPS65090_IRQ(_reg, _mask_pos) \
{ \
.mask_reg = (_reg), \
.mask_pos = (_mask_pos), \
- .type = (_type), \
}
static const struct tps65090_irq_data tps65090_irqs[] = {
- [0] = TPS65090_IRQ(0, 0, EVENT),
- [1] = TPS65090_IRQ(0, 1, EVENT),
- [2] = TPS65090_IRQ(0, 2, EVENT),
- [3] = TPS65090_IRQ(0, 3, EVENT),
- [4] = TPS65090_IRQ(0, 4, EVENT),
- [5] = TPS65090_IRQ(0, 5, EVENT),
- [6] = TPS65090_IRQ(0, 6, EVENT),
- [7] = TPS65090_IRQ(0, 7, EVENT),
- [8] = TPS65090_IRQ(1, 0, EVENT),
- [9] = TPS65090_IRQ(1, 1, EVENT),
- [10] = TPS65090_IRQ(1, 2, EVENT),
- [11] = TPS65090_IRQ(1, 3, EVENT),
- [12] = TPS65090_IRQ(1, 4, EVENT),
- [13] = TPS65090_IRQ(1, 5, EVENT),
- [14] = TPS65090_IRQ(1, 6, EVENT),
- [15] = TPS65090_IRQ(1, 7, EVENT),
+ [0] = TPS65090_IRQ(0, 0),
+ [1] = TPS65090_IRQ(0, 1),
+ [2] = TPS65090_IRQ(0, 2),
+ [3] = TPS65090_IRQ(0, 3),
+ [4] = TPS65090_IRQ(0, 4),
+ [5] = TPS65090_IRQ(0, 5),
+ [6] = TPS65090_IRQ(0, 6),
+ [7] = TPS65090_IRQ(0, 7),
+ [8] = TPS65090_IRQ(1, 0),
+ [9] = TPS65090_IRQ(1, 1),
+ [10] = TPS65090_IRQ(1, 2),
+ [11] = TPS65090_IRQ(1, 3),
+ [12] = TPS65090_IRQ(1, 4),
+ [13] = TPS65090_IRQ(1, 5),
+ [14] = TPS65090_IRQ(1, 6),
+ [15] = TPS65090_IRQ(1, 7),
};
-struct tps65090 {
- struct mutex lock;
- struct device *dev;
- struct i2c_client *client;
- struct regmap *rmap;
- struct irq_chip irq_chip;
- struct mutex irq_lock;
- int irq_base;
- u32 irq_en;
- u8 mask_cache[2];
- u8 mask_reg[2];
+static struct mfd_cell tps65090s[] = {
+ {
+ .name = "tps65910-pmic",
+ },
};
-int tps65090_write(struct device *dev, int reg, uint8_t val)
-{
- struct tps65090 *tps = dev_get_drvdata(dev);
- return regmap_write(tps->rmap, reg, val);
-}
-int tps65090_read(struct device *dev, int reg, uint8_t *val)
-{
- int rval, ret = 0;
- struct tps65090 *tps = dev_get_drvdata(dev);
- ret = regmap_read(tps->rmap, reg, &rval);
- *val = rval;
- return 0;
-}
-EXPORT_SYMBOL_GPL(tps65090_read);
-
-int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num)
-{
- struct tps65090 *tps = dev_get_drvdata(dev);
- return regmap_update_bits_lazy(tps->rmap, reg, BIT(bit_num), ~0u);
-
-}
-EXPORT_SYMBOL_GPL(tps65090_set_bits);
-
-int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num)
-{
- struct tps65090 *tps = dev_get_drvdata(dev);
- return regmap_update_bits_lazy(tps->rmap, reg, BIT(bit_num), 0u);
-}
-EXPORT_SYMBOL_GPL(tps65090_clr_bits);
-
-static int __remove_subdev(struct device *dev, void *unused)
-{
- platform_device_unregister(to_platform_device(dev));
- return 0;
-}
-
-static int tps65090_remove_subdevs(struct tps65090 *tps65090)
-{
- return device_for_each_child(tps65090->dev, NULL, __remove_subdev);
-}
static void tps65090_irq_lock(struct irq_data *data)
{
@@ -141,135 +83,97 @@ static void tps65090_irq_lock(struct irq_data *data)
static void tps65090_irq_mask(struct irq_data *irq_data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
- unsigned int __irq = irq_data->irq - tps65090->irq_base;
+ unsigned int __irq = irq_data->hwirq;
const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
- if (data->type == EVENT)
- tps65090->mask_reg[data->mask_reg] |= (1 << data->mask_pos);
- else
- tps65090->mask_reg[data->mask_reg] |= (3 << data->mask_pos);
-
- tps65090->irq_en &= ~(1 << __irq);
+ tps65090_set_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+ data->mask_pos);
}
static void tps65090_irq_unmask(struct irq_data *irq_data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
-
unsigned int __irq = irq_data->irq - tps65090->irq_base;
const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
- if (data->type == EVENT) {
- tps65090->mask_reg[data->mask_reg] &= ~(1 << data->mask_pos);
- tps65090->irq_en |= (1 << __irq);
- }
+ tps65090_clr_bits(tps65090->dev, (TPS65090_INT_MSK + data->mask_reg),
+ data->mask_pos);
}
static void tps65090_irq_sync_unlock(struct irq_data *data)
{
struct tps65090 *tps65090 = irq_data_get_irq_chip_data(data);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tps65090->mask_reg); i++) {
- if (tps65090->mask_reg[i] != tps65090->mask_cache[i]) {
- if (!WARN_ON(tps65090_write(tps65090->dev,
- TPS65090_INT_MSK + 2*i,
- tps65090->mask_reg[i])))
- tps65090->mask_cache[i] = tps65090->mask_reg[i];
- }
- }
mutex_unlock(&tps65090->irq_lock);
}
-static int tps65090_irq_set_type(struct irq_data *irq_data, unsigned int type)
-{
- struct tps65090 *tps65090 = irq_data_get_irq_chip_data(irq_data);
-
- unsigned int __irq = irq_data->irq - tps65090->irq_base;
- const struct tps65090_irq_data *data = &tps65090_irqs[__irq];
-
- if (data->type != EVENT) /* add support for GPIO, if needed */
- return -EINVAL;
-
- return 0;
-}
-
static irqreturn_t tps65090_irq(int irq, void *data)
{
struct tps65090 *tps65090 = data;
int ret = 0;
- u8 tmp[3];
- u8 int_ack;
- u32 acks, mask = 0;
+ u8 status = 0, mask = 0;
+ unsigned long int acks = 0;
int i;
- for (i = 0; i < 3; i++) {
- ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + 2*i,
- &tmp[i]);
+ for (i = 0; i < NUM_INT_REG; i++) {
+ ret = tps65090_read(tps65090->dev, TPS65090_INT_MSK + i, &mask);
if (ret < 0) {
dev_err(tps65090->dev,
- "failed to read interrupt status\n");
+ "failed to read mask reg [addr:%d]\n",
+ TPS65090_INT_MSK + i);
return IRQ_NONE;
}
- if (tmp[i]) {
- /* Ack only those interrupts which are enabled */
- int_ack = tmp[i] & (~(tps65090->mask_cache[i]));
+ ret = tps65090_read(tps65090->dev, TPS65090_INT_STS + i,
+ &status);
+ if (ret < 0) {
+ dev_err(tps65090->dev,
+ "failed to read status reg [addr:%d]\n",
+ TPS65090_INT_STS + i);
+ return IRQ_NONE;
+ }
+ if (status) {
+ /* Ack only those interrupts which are not masked */
+ status &= (~mask);
ret = tps65090_write(tps65090->dev,
- TPS65090_INT_STS + 2*i, int_ack);
+ TPS65090_INT_STS + i, status);
if (ret < 0) {
dev_err(tps65090->dev,
"failed to write interrupt status\n");
return IRQ_NONE;
}
+ acks |= (status << (i * 8));
}
}
- acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
-
- for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
- if (tps65090_irqs[i].type == EVENT)
- mask = (1 << (tps65090_irqs[i].mask_pos
- + tps65090_irqs[i].mask_reg*8));
- else
- return -EINVAL;
- if ((acks & mask) && (tps65090->irq_en & (1 << i)))
- handle_nested_irq(tps65090->irq_base + i);
- }
- return IRQ_HANDLED;
+ for_each_set_bit(i, &acks, ARRAY_SIZE(tps65090_irqs))
+ handle_nested_irq(tps65090->irq_base + i);
+ return acks ? IRQ_HANDLED : IRQ_NONE;
}
static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
- int irq_base)
+ int irq_base)
{
int i, ret;
if (!irq_base) {
- dev_warn(tps65090->dev, "No interrupt support on IRQ base\n");
+ dev_err(tps65090->dev, "IRQ base not set\n");
return -EINVAL;
}
mutex_init(&tps65090->irq_lock);
- tps65090->mask_reg[0] = 0xFF;
- tps65090->mask_reg[1] = 0xFF;
- for (i = 0; i < 2; i++) {
- tps65090->mask_cache[i] = tps65090->mask_reg[i];
- tps65090_write(tps65090->dev, TPS65090_INT_MSK + i,
- tps65090->mask_cache[i]);
- }
+ for (i = 0; i < NUM_INT_REG; i++)
+ tps65090_write(tps65090->dev, TPS65090_INT_MSK + i, 0xFF);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < NUM_INT_REG; i++)
tps65090_write(tps65090->dev, TPS65090_INT_STS + i, 0xff);
tps65090->irq_base = irq_base;
-
tps65090->irq_chip.name = "tps65090";
tps65090->irq_chip.irq_mask = tps65090_irq_mask;
tps65090->irq_chip.irq_unmask = tps65090_irq_unmask;
tps65090->irq_chip.irq_bus_lock = tps65090_irq_lock;
tps65090->irq_chip.irq_bus_sync_unlock = tps65090_irq_sync_unlock;
- tps65090->irq_chip.irq_set_type = tps65090_irq_set_type;
for (i = 0; i < ARRAY_SIZE(tps65090_irqs); i++) {
int __irq = i + tps65090->irq_base;
@@ -292,90 +196,21 @@ static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq,
return ret;
}
-static int __devinit tps65090_add_subdevs(struct tps65090 *tps65090,
- struct tps65090_platform_data *pdata)
-{
- struct tps65090_subdev_info *subdev;
- struct platform_device *pdev;
- int i, ret = 0;
-
- for (i = 0; i < pdata->num_subdevs; i++) {
- subdev = &pdata->subdevs[i];
-
- pdev = platform_device_alloc(subdev->name, subdev->id);
-
- pdev->dev.parent = tps65090->dev;
- pdev->dev.platform_data = subdev->platform_data;
-
- ret = platform_device_add(pdev);
- if (ret)
- goto failed;
- }
- return 0;
-
-failed:
- tps65090_remove_subdevs(tps65090);
- return ret;
-}
-#ifdef CONFIG_DEBUG_FS
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-static void print_regs(const char *header, struct seq_file *s,
- struct i2c_client *client, int start_offset,
- int end_offset)
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
{
- int reg_val;
- int i;
- int ret;
- struct tps65090 *tps = s->private;
- seq_printf(s, "%s\n", header);
- for (i = start_offset; i <= end_offset; ++i) {
- ret = regmap_read(tps->rmap, i, &reg_val);
- if (ret >= 0)
- seq_printf(s, "Reg 0x%02x Value 0x%02x\n", i, reg_val);
- }
- seq_printf(s, "------------------\n");
-}
-
-static int dbg_tps_show(struct seq_file *s, void *unused)
-{
- struct tps65090 *tps = s->private;
- struct i2c_client *client = tps->client;
-
- seq_printf(s, "TPS65090 Registers\n");
- seq_printf(s, "------------------\n");
-
- print_regs("All Regs", s, client, 0x0, 24);
- return 0;
-}
-
-static int dbg_tps_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dbg_tps_show, inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
- .open = dbg_tps_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void __init tps65090_debuginit(struct tps65090 *tps)
-{
- (void)debugfs_create_file("tps65090", S_IRUGO, NULL,
- tps, &debug_fops);
-}
-#else
-static void __init tps65090_debuginit(struct tps65090 *tpsi)
-{
- return;
+ if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS))
+ return true;
+ else
+ return false;
}
-#endif
static const struct regmap_config tps65090_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+ .max_register = TOTAL_NUM_REG,
+ .num_reg_defaults_raw = TOTAL_NUM_REG,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = is_volatile_reg,
};
static int __devinit tps65090_i2c_probe(struct i2c_client *client,
@@ -387,50 +222,47 @@ static int __devinit tps65090_i2c_probe(struct i2c_client *client,
if (!pdata) {
dev_err(&client->dev, "tps65090 requires platform data\n");
- return -ENOTSUPP;
+ return -EINVAL;
}
- tps65090 = kzalloc(sizeof(struct tps65090), GFP_KERNEL);
- if (tps65090 == NULL)
+ tps65090 = devm_kzalloc(&client->dev, sizeof(*tps65090), GFP_KERNEL);
+ if (!tps65090) {
+ dev_err(&client->dev, "mem alloc for tps65090 failed\n");
return -ENOMEM;
+ }
- tps65090->client = client;
tps65090->dev = &client->dev;
i2c_set_clientdata(client, tps65090);
- mutex_init(&tps65090->lock);
+ tps65090->rmap = devm_regmap_init_i2c(client, &tps65090_regmap_config);
+ if (IS_ERR(tps65090->rmap)) {
+ ret = PTR_ERR(tps65090->rmap);
+ dev_err(&client->dev, "regmap_init failed with err: %d\n", ret);
+ return ret;
+ }
if (client->irq) {
- ret = tps65090_irq_init(tps65090, client->irq,
- pdata->irq_base);
+ ret = tps65090_irq_init(tps65090, client->irq, pdata->irq_base);
if (ret) {
- dev_err(&client->dev, "IRQ init failed: %d\n", ret);
- goto err_irq_init;
+ dev_err(&client->dev, "IRQ init failed with err: %d\n",
+ ret);
+ return ret;
}
}
- ret = tps65090_add_subdevs(tps65090, pdata);
+ ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
+ ARRAY_SIZE(tps65090s), NULL, 0);
if (ret) {
- dev_err(&client->dev, "add devices failed: %d\n", ret);
- goto err_add_devs;
+ dev_err(&client->dev, "add mfd devices failed with err: %d\n",
+ ret);
+ goto err_irq_exit;
}
- tps65090->rmap = regmap_init_i2c(tps65090->client,
- &tps65090_regmap_config);
- if (IS_ERR(tps65090->rmap)) {
- dev_err(&client->dev, "regmap_init failed: %ld\n",
- PTR_ERR(tps65090->rmap));
- goto err_add_devs;
- };
- tps65090_debuginit(tps65090);
-
return 0;
-err_add_devs:
+err_irq_exit:
if (client->irq)
free_irq(client->irq, tps65090);
-err_irq_init:
- kfree(tps65090);
return ret;
}
@@ -438,29 +270,34 @@ static int __devexit tps65090_i2c_remove(struct i2c_client *client)
{
struct tps65090 *tps65090 = i2c_get_clientdata(client);
+ mfd_remove_devices(tps65090->dev);
if (client->irq)
free_irq(client->irq, tps65090);
- regmap_exit(tps65090->rmap);
- kfree(tps65090);
return 0;
}
-#ifdef CONFIG_PM
-static int tps65090_i2c_suspend(struct i2c_client *client, pm_message_t state)
+
+#ifdef CONFIG_PM_SLEEP
+static int tps65090_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
if (client->irq)
disable_irq(client->irq);
return 0;
}
-static int tps65090_i2c_resume(struct i2c_client *client)
+static int tps65090_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
if (client->irq)
enable_irq(client->irq);
return 0;
}
#endif
+static const struct dev_pm_ops tps65090_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tps65090_suspend, tps65090_resume)
+};
static const struct i2c_device_id tps65090_id_table[] = {
{ "tps65090", 0 },
@@ -472,13 +309,10 @@ static struct i2c_driver tps65090_driver = {
.driver = {
.name = "tps65090",
.owner = THIS_MODULE,
+ .pm = &tps65090_pm_ops,
},
.probe = tps65090_i2c_probe,
.remove = __devexit_p(tps65090_i2c_remove),
-#ifdef CONFIG_PM
- .suspend = tps65090_i2c_suspend,
- .resume = tps65090_i2c_resume,
-#endif
.id_table = tps65090_id_table,
};
@@ -495,4 +329,5 @@ static void __exit tps65090_exit(void)
module_exit(tps65090_exit);
MODULE_DESCRIPTION("TPS65090 core driver");
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c
index f0f2ce1f6840..002b7d022d70 100644
--- a/drivers/mfd/tps80031.c
+++ b/drivers/mfd/tps80031.c
@@ -30,6 +30,7 @@
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/pm.h>
+#include <linux/regmap.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps80031.h>
@@ -108,6 +109,43 @@
#define TPS80031_BBSPOR_CFG 0xE6
#define TPS80031_BBSPOR_CHG_EN 0x8
+/* Valid Address ranges */
+#define TPS80031_ID0_PMIC_SLAVE_SMPS_DVS 0x55 ... 0x5C
+
+#define TPS80031_ID1_RTC 0x00 ... 0x16
+#define TPS80031_ID1_MEMORY 0x17 ... 0x1E
+#define TPS80031_ID1_PMC_MASTER 0x1F ... 0x2D
+#define TPS80031_ID1_PMC_SLAVE_MISC 0x31 ... 0x34
+#define TPS80031_ID1_PMC_SLAVE_SMPS 0x40 ... 0x68
+#define TPS80031_ID1_PMC_SLAVE_LDO 0x80 ... 0xA7
+#define TPS80031_ID1_PMC_SLAVE_REOSURCES 0XAD ... 0xD0
+#define TPS80031_ID1_PMC_PREQ_ASSIGN 0XD7 ... 0xDF
+#define TPS80031_ID1_PMC_MISC 0xE2 ... 0xEF
+#define TPS80031_ID1_PMC_PU_PD_HZ 0xF0 ... 0xF6
+#define TPS80031_ID1_PMC_BACKUP 0xFA
+
+#define TPS80031_ID2_USB 0x00 ... 0x1A
+#define TPS80031_ID2_GPADC_CONTROL 0x2E ... 0x36
+#define TPS80031_ID2_GPADC_RESULTS 0x37 ... 0x3C
+#define TPS80031_ID2_AUXILLIARIES 0x90 ... 0x9C
+#define TPS80031_ID2_CUSTOM 0xA0 ... 0xB9
+#define TPS80031_ID2_PWM 0xBA ... 0xBE
+#define TPS80031_ID2_FUEL_GAUSE 0xC0 ... 0xCB
+#define TPS80031_ID2_INTERFACE_INTERRUPTS 0xD0 ... 0xD8
+#define TPS80031_ID2_CHARGER 0xDA ... 0xF5
+
+#define TPS80031_ID3_TEST_LDO 0x00 ... 0x09
+#define TPS80031_ID3_TEST_SMPS 0x10 ... 0x2B
+#define TPS80031_ID3_TEST_POWER 0x30 ... 0x36
+#define TPS80031_ID3_TEST_CHARGER 0x40 ... 0x48
+#define TPS80031_ID3_TEST_AUXILIIARIES 0x50 ... 0xB1
+
+#define TPS80031_ID3_DIEID 0xC0 ... 0xC8
+#define TPS80031_ID3_TRIM_PHOENIX 0xCC ... 0xEA
+#define TPS80031_ID3_TRIM_CUSTOM 0xEC ... 0xED
+
+#define TPS80031_MAX_REGISTER 0x100
+
struct tps80031_pupd_data {
u8 reg;
u8 pullup_bit;
@@ -256,159 +294,84 @@ struct tps80031 {
u8 cont_int_en;
u8 prev_cont_stat1;
struct tps80031_client tps_clients[TPS_NUM_SLAVES];
+ struct regmap *regmap[TPS_NUM_SLAVES];
};
-static inline int __tps80031_read(struct i2c_client *client,
- int reg, uint8_t *val)
-{
- int ret;
-
- ret = i2c_smbus_read_byte_data(client, reg);
- if (ret < 0) {
- dev_err(&client->dev,
- "failed reading from addr 0x%02x, reg 0x%02x\n",
- client->addr, reg);
- return ret;
- }
-
- *val = (uint8_t)ret;
-
- return 0;
-}
-
-static inline int __tps80031_reads(struct i2c_client *client, int reg,
- int len, uint8_t *val)
-{
- int ret;
-
- ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
- if (ret < 0) {
- dev_err(&client->dev,
- "failed reading from addr 0x%02x, reg 0x%02x\n",
- client->addr, reg);
- return ret;
- }
-
- return 0;
-}
-
-static inline int __tps80031_write(struct i2c_client *client,
- int reg, uint8_t val)
-{
- int ret;
- ret = i2c_smbus_write_byte_data(client, reg, val);
- if (ret < 0) {
- dev_err(&client->dev,
- "failed writing 0x%02x to 0x%02x\n", val, reg);
- return ret;
- }
-
- return 0;
-}
-
-static inline int __tps80031_writes(struct i2c_client *client, int reg,
- int len, uint8_t *val)
-{
- int ret;
-
- ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
- if (ret < 0) {
- dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
- return ret;
- }
+/* TPS80031 sub mfd devices */
+static struct mfd_cell tps80031_cell[] = {
+ {
+ .name = "tps80031-regulators",
+ },
+ {
+ .name = "tps80031-rtc",
+ },
+ {
+ .name = "tps80031-gpadc",
+ },
+ {
+ .name = "tps80031-battery-gauge",
+ },
+ {
+ .name = "tps80031-charger",
+ },
+};
- return 0;
-}
int tps80031_write(struct device *dev, int sid, int reg, uint8_t val)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
- int ret;
- mutex_lock(&tps->lock);
- ret = __tps80031_write(tps->client, reg, val);
- mutex_unlock(&tps->lock);
-
- return ret;
+ return regmap_write(tps80031->regmap[sid], reg, val);
}
EXPORT_SYMBOL_GPL(tps80031_write);
int tps80031_writes(struct device *dev, int sid, int reg, int len, uint8_t *val)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
- int ret;
- mutex_lock(&tps->lock);
- ret = __tps80031_writes(tps->client, reg, len, val);
- mutex_unlock(&tps->lock);
-
- return ret;
+ return regmap_bulk_write(tps80031->regmap[sid], reg, val, len);
}
EXPORT_SYMBOL_GPL(tps80031_writes);
int tps80031_read(struct device *dev, int sid, int reg, uint8_t *val)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
+ unsigned int ival;
+ int ret;
- return __tps80031_read(tps->client, reg, val);
+ ret = regmap_read(tps80031->regmap[sid], reg, &ival);
+ if (ret < 0) {
+ dev_err(dev, "failed reading from reg 0x%02x\n", reg);
+ return ret;
+ }
+
+ *val = ival;
+ return ret;
}
EXPORT_SYMBOL_GPL(tps80031_read);
int tps80031_reads(struct device *dev, int sid, int reg, int len, uint8_t *val)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
- return __tps80031_reads(tps->client, reg, len, val);
+ return regmap_bulk_read(tps80031->regmap[sid], reg, val, len);
}
EXPORT_SYMBOL_GPL(tps80031_reads);
int tps80031_set_bits(struct device *dev, int sid, int reg, uint8_t bit_mask)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
- uint8_t reg_val;
- int ret = 0;
-
- mutex_lock(&tps->lock);
-
- ret = __tps80031_read(tps->client, reg, &reg_val);
- if (ret)
- goto out;
- if ((reg_val & bit_mask) != bit_mask) {
- reg_val |= bit_mask;
- ret = __tps80031_write(tps->client, reg, reg_val);
- }
-out:
- mutex_unlock(&tps->lock);
- return ret;
+ return regmap_update_bits(tps80031->regmap[sid], reg,
+ bit_mask, bit_mask);
}
EXPORT_SYMBOL_GPL(tps80031_set_bits);
int tps80031_clr_bits(struct device *dev, int sid, int reg, uint8_t bit_mask)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
- uint8_t reg_val;
- int ret = 0;
-
- mutex_lock(&tps->lock);
- ret = __tps80031_read(tps->client, reg, &reg_val);
- if (ret)
- goto out;
-
- if (reg_val & bit_mask) {
- reg_val &= ~bit_mask;
- ret = __tps80031_write(tps->client, reg, reg_val);
- }
-out:
- mutex_unlock(&tps->lock);
- return ret;
+ return regmap_update_bits(tps80031->regmap[sid], reg, bit_mask, 0);
}
EXPORT_SYMBOL_GPL(tps80031_clr_bits);
@@ -416,23 +379,8 @@ int tps80031_update(struct device *dev, int sid, int reg, uint8_t val,
uint8_t mask)
{
struct tps80031 *tps80031 = dev_get_drvdata(dev);
- struct tps80031_client *tps = &tps80031->tps_clients[sid];
- uint8_t reg_val;
- int ret = 0;
- mutex_lock(&tps->lock);
-
- ret = __tps80031_read(tps->client, reg, &reg_val);
- if (ret)
- goto out;
-
- if ((reg_val & mask) != val) {
- reg_val = (reg_val & ~mask) | (val & mask);
- ret = __tps80031_write(tps->client, reg, reg_val);
- }
-out:
- mutex_unlock(&tps->lock);
- return ret;
+ return regmap_update_bits(tps80031->regmap[sid], reg, mask, val);
}
EXPORT_SYMBOL_GPL(tps80031_update);
@@ -446,12 +394,12 @@ int tps80031_force_update(struct device *dev, int sid, int reg, uint8_t val,
mutex_lock(&tps->lock);
- ret = __tps80031_read(tps->client, reg, &reg_val);
+ ret = tps80031_read(dev, sid, reg, &reg_val);
if (ret)
goto out;
reg_val = (reg_val & ~mask) | (val & mask);
- ret = __tps80031_write(tps->client, reg, reg_val);
+ ret = tps80031_write(dev, sid, reg, reg_val);
out:
mutex_unlock(&tps->lock);
@@ -544,7 +492,8 @@ static void tps80031_power_off(void)
if (!tps->client)
return;
dev_info(&tps->client->dev, "switching off PMU\n");
- __tps80031_write(tps->client, TPS80031_PHOENIX_DEV_ON, DEVOFF);
+ tps80031_write(&tps->client->dev, SLAVE_ID1,
+ TPS80031_PHOENIX_DEV_ON, DEVOFF);
}
static void tps80031_pupd_init(struct tps80031 *tps80031,
@@ -589,7 +538,7 @@ static void tps80031_init_ext_control(struct tps80031 *tps80031,
/* Clear all external control for this rail */
for (i = 0; i < 9; ++i) {
- tps80031_write(tps80031->dev, SLAVE_ID1,
+ ret = tps80031_write(tps80031->dev, SLAVE_ID1,
TPS80031_PREQ1_RES_ASS_A + i, 0);
if (ret < 0)
dev_err(tps80031->dev, "%s() Error in clearing "
@@ -613,14 +562,14 @@ static int tps80031_gpio_get(struct gpio_chip *gc, unsigned offset)
uint8_t trans;
int ret;
- ret = __tps80031_read(tps->client,
+ ret = tps80031_read(&tps->client->dev, SLAVE_ID1,
pmc_ext_control_base[offset] +
EXT_CONTROL_CFG_STATE, &state);
if (ret)
return ret;
if (state != 0) {
- ret = __tps80031_read(tps->client,
+ ret = tps80031_read(&tps->client->dev, SLAVE_ID1,
pmc_ext_control_base[offset] +
EXT_CONTROL_CFG_TRANS, &trans);
if (ret)
@@ -742,17 +691,6 @@ static void tps80031_gpio_init(struct tps80031 *tps80031,
dev_warn(tps80031->dev, "GPIO registration failed: %d\n", ret);
}
-static int __remove_subdev(struct device *dev, void *unused)
-{
- platform_device_unregister(to_platform_device(dev));
- return 0;
-}
-
-static int tps80031_remove_subdevs(struct tps80031 *tps80031)
-{
- return device_for_each_child(tps80031->dev, NULL, __remove_subdev);
-}
-
static void tps80031_irq_lock(struct irq_data *data)
{
struct tps80031 *tps80031 = irq_data_get_irq_chip_data(data);
@@ -1075,32 +1013,6 @@ static void tps80031_clk32k_init(struct tps80031 *tps80031,
}
}
-static int __devinit tps80031_add_subdevs(struct tps80031 *tps80031,
- struct tps80031_platform_data *pdata)
-{
- struct tps80031_subdev_info *subdev;
- struct platform_device *pdev;
- int i, ret = 0;
-
- for (i = 0; i < pdata->num_subdevs; i++) {
- subdev = &pdata->subdevs[i];
-
- pdev = platform_device_alloc(subdev->name, subdev->id);
-
- pdev->dev.parent = tps80031->dev;
- pdev->dev.platform_data = subdev->platform_data;
-
- ret = platform_device_add(pdev);
- if (ret)
- goto failed;
- }
- return 0;
-
-failed:
- tps80031_remove_subdevs(tps80031);
- return ret;
-}
-
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/seq_file.h>
@@ -1115,7 +1027,7 @@ static void print_regs(const char *header, struct seq_file *s,
seq_printf(s, "%s\n", header);
for (i = start_offset; i <= end_offset; ++i) {
- ret = __tps80031_read(tps->client, i, &reg_val);
+ ret = tps80031_read(&tps->client->dev, sid, i, &reg_val);
if (ret >= 0)
seq_printf(s, "Addr = 0x%02x Reg 0x%02x Value 0x%02x\n",
tps->client->addr, i, reg_val);
@@ -1189,11 +1101,116 @@ static void __init tps80031_debuginit(struct tps80031 *tpsi)
}
#endif
+static bool rd_wr_reg_id0(struct device *dev, unsigned int reg)
+{
+ switch(reg) {
+ case TPS80031_ID0_PMIC_SLAVE_SMPS_DVS:
+ return true;
+ default:
+ pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg);
+ BUG();
+ return false;
+ }
+}
+
+static bool rd_wr_reg_id1(struct device *dev, unsigned int reg)
+{
+ switch(reg) {
+ case TPS80031_ID1_RTC:
+ case TPS80031_ID1_MEMORY:
+ case TPS80031_ID1_PMC_MASTER:
+ case TPS80031_ID1_PMC_SLAVE_SMPS:
+ case TPS80031_ID1_PMC_SLAVE_MISC:
+ case TPS80031_ID1_PMC_SLAVE_LDO:
+ case TPS80031_ID1_PMC_SLAVE_REOSURCES:
+ case TPS80031_ID1_PMC_PREQ_ASSIGN:
+ case TPS80031_ID1_PMC_MISC:
+ case TPS80031_ID1_PMC_PU_PD_HZ:
+ case TPS80031_ID1_PMC_BACKUP:
+ return true;
+ default:
+ pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg);
+ BUG();
+ return false;
+ }
+}
+
+static bool rd_wr_reg_id2(struct device *dev, unsigned int reg)
+{
+ switch(reg) {
+ case TPS80031_ID2_USB:
+ case TPS80031_ID2_GPADC_CONTROL:
+ case TPS80031_ID2_GPADC_RESULTS:
+ case TPS80031_ID2_AUXILLIARIES:
+ case TPS80031_ID2_CUSTOM:
+ case TPS80031_ID2_PWM:
+ case TPS80031_ID2_FUEL_GAUSE:
+ case TPS80031_ID2_INTERFACE_INTERRUPTS:
+ case TPS80031_ID2_CHARGER:
+ return true;
+ default:
+ pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg);
+ BUG();
+ return false;
+ }
+}
+static bool rd_wr_reg_id3(struct device *dev, unsigned int reg)
+{
+ switch(reg) {
+ case TPS80031_ID3_TEST_LDO:
+ case TPS80031_ID3_TEST_SMPS:
+ case TPS80031_ID3_TEST_POWER:
+ case TPS80031_ID3_TEST_CHARGER:
+ case TPS80031_ID3_TEST_AUXILIIARIES:
+ case TPS80031_ID3_DIEID:
+ case TPS80031_ID3_TRIM_PHOENIX:
+ case TPS80031_ID3_TRIM_CUSTOM:
+ return true;
+ default:
+ pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg);
+ BUG();
+ return false;
+ }
+}
+
+static const struct regmap_config tps80031_regmap_configs[] = {
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = rd_wr_reg_id0,
+ .readable_reg = rd_wr_reg_id0,
+ .max_register = TPS80031_MAX_REGISTER - 1,
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = rd_wr_reg_id1,
+ .readable_reg = rd_wr_reg_id1,
+ .max_register = TPS80031_MAX_REGISTER - 1,
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = rd_wr_reg_id2,
+ .readable_reg = rd_wr_reg_id2,
+ .max_register = TPS80031_MAX_REGISTER - 1,
+ },
+ {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .writeable_reg = rd_wr_reg_id3,
+ .readable_reg = rd_wr_reg_id3,
+ .max_register = TPS80031_MAX_REGISTER - 1,
+ },
+};
+
static int __devexit tps80031_i2c_remove(struct i2c_client *client)
{
struct tps80031 *tps80031 = i2c_get_clientdata(client);
int i;
+ mfd_remove_devices(tps80031->dev);
+
if (client->irq)
free_irq(client->irq, tps80031);
@@ -1209,7 +1226,6 @@ static int __devexit tps80031_i2c_remove(struct i2c_client *client)
mutex_destroy(&tps->lock);
}
- kfree(tps80031);
return 0;
}
@@ -1246,9 +1262,11 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
dev_info(&client->dev, "Jtag version 0x%02x and Eeprom version 0x%02x\n",
jtag_ver, ep_ver);
- tps80031 = kzalloc(sizeof(struct tps80031), GFP_KERNEL);
- if (tps80031 == NULL)
+ tps80031 = devm_kzalloc(&client->dev, sizeof(*tps80031), GFP_KERNEL);
+ if (!tps80031) {
+ dev_err(&client->dev, "Memory alloc for tps80031 failed\n");
return -ENOMEM;
+ }
tps80031->es_version = jtag_ver;
tps80031->dev = &client->dev;
@@ -1270,10 +1288,19 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
if (!tps->client) {
dev_err(&client->dev, "can't attach client %d\n", i);
ret = -ENOMEM;
- goto fail;
+ goto fail_client_reg;
}
i2c_set_clientdata(tps->client, tps80031);
mutex_init(&tps->lock);
+
+ tps80031->regmap[i] = devm_regmap_init_i2c(tps->client,
+ &tps80031_regmap_configs[i]);
+ if (IS_ERR(tps80031->regmap[i])) {
+ ret = PTR_ERR(tps80031->regmap[i]);
+ dev_err(&client->dev,
+ "regmap %d init failed, err %d\n", i, ret);
+ goto fail_client_reg;
+ }
}
if (client->irq) {
@@ -1281,7 +1308,7 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
pdata->irq_base);
if (ret) {
dev_err(&client->dev, "IRQ init failed: %d\n", ret);
- goto fail;
+ goto fail_client_reg;
}
}
@@ -1289,10 +1316,11 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
tps80031_init_ext_control(tps80031, pdata);
- ret = tps80031_add_subdevs(tps80031, pdata);
- if (ret) {
- dev_err(&client->dev, "add devices failed: %d\n", ret);
- goto fail;
+ ret = mfd_add_devices(tps80031->dev, -1,
+ tps80031_cell, ARRAY_SIZE(tps80031_cell), NULL, 0);
+ if (ret < 0) {
+ dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret);
+ goto fail_mfd_add;
}
tps80031_gpio_init(tps80031, pdata);
@@ -1310,14 +1338,24 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client,
return 0;
-fail:
- tps80031_i2c_remove(client);
+fail_mfd_add:
+ if (client->irq)
+ free_irq(client->irq, tps80031);
+fail_client_reg:
+ for (i = 0; i < TPS_NUM_SLAVES; i++) {
+ struct tps80031_client *tps = &tps80031->tps_clients[i];
+ if (tps->client && tps->client != client)
+ i2c_unregister_device(tps->client);
+ tps80031->tps_clients[i].client = NULL;
+ mutex_destroy(&tps->lock);
+ }
return ret;
}
#ifdef CONFIG_PM
-static int tps80031_i2c_suspend(struct i2c_client *client, pm_message_t state)
+static int tps80031_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct tps80031 *tps80031 = i2c_get_clientdata(client);
if (client->irq)
disable_irq(client->irq);
@@ -1325,14 +1363,22 @@ static int tps80031_i2c_suspend(struct i2c_client *client, pm_message_t state)
return 0;
}
-static int tps80031_i2c_resume(struct i2c_client *client)
+static int tps80031_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct tps80031 *tps80031 = i2c_get_clientdata(client);
tps80031_backup_battery_charger_control(tps80031, 1);
if (client->irq)
enable_irq(client->irq);
return 0;
}
+static const struct dev_pm_ops tps80031_dev_pm_ops = {
+ .suspend = tps80031_i2c_suspend,
+ .resume = tps80031_i2c_resume,
+};
+#define TPS80031_DEV_PM (&tps80031_dev_pm_ops)
+#else
+#define TPS80031_DEV_PM NULL
#endif
@@ -1346,13 +1392,10 @@ static struct i2c_driver tps80031_driver = {
.driver = {
.name = "tps80031",
.owner = THIS_MODULE,
+ .pm = TPS80031_DEV_PM,
},
.probe = tps80031_i2c_probe,
.remove = __devexit_p(tps80031_i2c_remove),
-#ifdef CONFIG_PM
- .suspend = tps80031_i2c_suspend,
- .resume = tps80031_i2c_resume,
-#endif
.id_table = tps80031_id_table,
};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dcf345e23487..0d6210e50e43 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -568,6 +568,13 @@ config THERM_EST
---help---
Thermal driver which estimates temperature based of other sensors.
+config TEGRA_THROUGHPUT
+ bool "Device node to set throughput target"
+ depends on TEGRA_DC && TEGRA_DC_EXTENSIONS
+ default y
+ ---help---
+ Dev node /dev/tegra-throughput used to set a throughput target.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index d9172c99bf6d..0912d6d2ea53 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -55,8 +55,10 @@ obj-$(CONFIG_SENSORS_AK8975) += akm8975.o
obj-$(CONFIG_SENSORS_NCT1008) += nct1008.o
obj-$(CONFIG_BCM4329_RFKILL) += bcm4329_rfkill.o
obj-$(CONFIG_INV_SENSORS) += inv_mpu/
+CFLAGS_tegra-cryptodev.o = -Werror
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
+obj-$(CONFIG_TEGRA_THROUGHPUT) += tegra-throughput.o
diff --git a/drivers/misc/bcm4329_rfkill.c b/drivers/misc/bcm4329_rfkill.c
index 9dc33fd51e59..a2d5ca6699cc 100644
--- a/drivers/misc/bcm4329_rfkill.c
+++ b/drivers/misc/bcm4329_rfkill.c
@@ -107,7 +107,6 @@ static int bcm4329_rfkill_probe(struct platform_device *pdev)
"bcm4329_nreset_gpio");
if (res) {
bcm4329_rfkill->gpio_reset = res->start;
- tegra_gpio_enable(bcm4329_rfkill->gpio_reset);
ret = gpio_request(bcm4329_rfkill->gpio_reset,
"bcm4329_nreset_gpio");
} else {
@@ -121,7 +120,6 @@ static int bcm4329_rfkill_probe(struct platform_device *pdev)
"bcm4329_nshutdown_gpio");
if (res) {
bcm4329_rfkill->gpio_shutdown = res->start;
- tegra_gpio_enable(bcm4329_rfkill->gpio_shutdown);
ret = gpio_request(bcm4329_rfkill->gpio_shutdown,
"bcm4329_nshutdown_gpio");
} else {
diff --git a/drivers/misc/inv_mpu/mpu6050/mldl_cfg.c b/drivers/misc/inv_mpu/mpu6050/mldl_cfg.c
index 22af0c200985..920f4ae8a4b7 100644
--- a/drivers/misc/inv_mpu/mpu6050/mldl_cfg.c
+++ b/drivers/misc/inv_mpu/mpu6050/mldl_cfg.c
@@ -1786,6 +1786,16 @@ int inv_mpu_suspend(struct mldl_cfg *mldl_cfg,
return result;
}
}
+ /* Disable irq when suspend all sensors */
+ if (sensors == INV_ALL_SENSORS) {
+ result = inv_serial_single_write(
+ gyro_handle, mldl_cfg->mpu_chip_info->addr,
+ MPUREG_INT_ENABLE, 0);
+ if (result) {
+ LOG_RESULT_LOCATION(result);
+ return result;
+ }
+ }
mldl_cfg->inv_mpu_cfg->requested_sensors = (~sensors) & INV_ALL_SENSORS;
return result;
diff --git a/drivers/misc/tegra-baseband/bb-m7400.c b/drivers/misc/tegra-baseband/bb-m7400.c
index adabefdb100d..edde7d1786ed 100644
--- a/drivers/misc/tegra-baseband/bb-m7400.c
+++ b/drivers/misc/tegra-baseband/bb-m7400.c
@@ -241,7 +241,7 @@ static int m7400_attrib_write(struct device *dev, int value)
} else {
/* Unregister ehci controller */
if (ehci_device != NULL)
- pdata->ehci_unregister(ehci_device);
+ pdata->ehci_unregister(&ehci_device);
/* Signal AP going down */
m7400_apdown_handshake();
diff --git a/drivers/misc/tegra-baseband/bb-power.c b/drivers/misc/tegra-baseband/bb-power.c
index 9210a8f3e84a..c070fd45160e 100644
--- a/drivers/misc/tegra-baseband/bb-power.c
+++ b/drivers/misc/tegra-baseband/bb-power.c
@@ -71,9 +71,6 @@ static int tegra_bb_power_gpio_init(struct tegra_bb_power_gdata *gdata)
else
gpio_direction_output(gpio_id, (!gpio_flags ? 0 : 1));
- /* Enable the gpio */
- tegra_gpio_enable(gpio_id);
-
/* Create a sysfs node, if requested */
if (gpiolist->doexport)
gpio_export(gpio_id, false);
diff --git a/drivers/misc/tegra-cec/Makefile b/drivers/misc/tegra-cec/Makefile
index ab380305c35f..8bac2a519046 100644
--- a/drivers/misc/tegra-cec/Makefile
+++ b/drivers/misc/tegra-cec/Makefile
@@ -2,4 +2,6 @@
# Makefile for tegra cec support.
#
+subdir-ccflags-y = -Werror
+
obj-$(CONFIG_TEGRA_CEC_T30) += tegra_cec.o
diff --git a/drivers/misc/tegra-throughput.c b/drivers/misc/tegra-throughput.c
new file mode 100644
index 000000000000..d491ef8c06cf
--- /dev/null
+++ b/drivers/misc/tegra-throughput.c
@@ -0,0 +1,242 @@
+/*
+ * drivers/misc/throughput.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, 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/kthread.h>
+#include <linux/ktime.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/throughput_ioctl.h>
+#include <linux/nvhost.h>
+#include <mach/dc.h>
+
+#define DEFAULT_SYNC_RATE 60000 /* 60 Hz */
+
+static unsigned short target_frame_time;
+static unsigned short last_frame_time;
+static ktime_t last_flip;
+static unsigned int multiple_app_disable;
+static spinlock_t lock;
+
+static struct work_struct work;
+static int throughput_hint;
+
+static void set_throughput_hint(struct work_struct *work)
+{
+ /* notify throughput hint clients here */
+ nvhost_scale3d_set_throughput_hint(throughput_hint);
+}
+
+static int throughput_flip_callback(void)
+{
+ long timediff;
+ ktime_t now;
+
+ /* only register flips when a single app is active */
+ if (multiple_app_disable)
+ return NOTIFY_DONE;
+
+ now = ktime_get();
+ if (last_flip.tv64 != 0) {
+ timediff = (long) ktime_us_delta(now, last_flip);
+ if (timediff > (long) USHRT_MAX)
+ last_frame_time = USHRT_MAX;
+ else
+ last_frame_time = (unsigned short) timediff;
+
+ if (last_frame_time == 0) {
+ pr_warn("%s: flips %lld nsec apart\n",
+ __func__, now.tv64 - last_flip.tv64);
+ return NOTIFY_DONE;
+ }
+
+ throughput_hint =
+ ((int) target_frame_time * 1000) / last_frame_time;
+
+ if (!work_pending(&work))
+ schedule_work(&work);
+ }
+ last_flip = now;
+
+ return NOTIFY_OK;
+}
+
+static int sync_rate;
+static int throughput_active_app_count;
+
+static void reset_target_frame_time(void)
+{
+ if (sync_rate == 0) {
+ sync_rate = tegra_dc_get_panel_sync_rate();
+
+ if (sync_rate == 0)
+ sync_rate = DEFAULT_SYNC_RATE;
+ }
+
+ target_frame_time = (unsigned short) (1000000000 / sync_rate);
+
+ pr_debug("%s: panel sync rate %d, target frame time %u\n",
+ __func__, sync_rate, target_frame_time);
+}
+
+static int callback_initialized;
+
+static int throughput_open(struct inode *inode, struct file *file)
+{
+ spin_lock(&lock);
+
+ if (!callback_initialized) {
+ callback_initialized = 1;
+ tegra_dc_set_flip_callback(throughput_flip_callback);
+ }
+
+ throughput_active_app_count++;
+ if (throughput_active_app_count > 1)
+ multiple_app_disable = 1;
+
+ spin_unlock(&lock);
+
+
+ pr_debug("throughput_open node %p file %p\n", inode, file);
+
+ return 0;
+}
+
+static int throughput_release(struct inode *inode, struct file *file)
+{
+ spin_lock(&lock);
+
+ throughput_active_app_count--;
+ if (throughput_active_app_count == 0) {
+ reset_target_frame_time();
+ multiple_app_disable = 0;
+ callback_initialized = 0;
+ tegra_dc_unset_flip_callback();
+ }
+
+ spin_unlock(&lock);
+
+ pr_debug("throughput_release node %p file %p\n", inode, file);
+
+ return 0;
+}
+
+static int throughput_set_target_fps(unsigned long arg)
+{
+ int disable;
+
+ pr_debug("%s: target fps %lu requested\n", __func__, arg);
+
+ disable = multiple_app_disable;
+
+ if (disable) {
+ pr_debug("%s: %d active apps, disabling fps usage\n",
+ __func__, throughput_active_app_count);
+ return 0;
+ }
+
+ if (arg == 0)
+ reset_target_frame_time();
+ else {
+ unsigned long frame_time = (1000000 / arg);
+
+ if (frame_time > USHRT_MAX)
+ frame_time = USHRT_MAX;
+
+ target_frame_time = (unsigned short) frame_time;
+ }
+
+ return 0;
+}
+
+static long
+throughput_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int err = 0;
+
+ if ((_IOC_TYPE(cmd) != TEGRA_THROUGHPUT_MAGIC) ||
+ (_IOC_NR(cmd) == 0) ||
+ (_IOC_NR(cmd) > TEGRA_THROUGHPUT_IOCTL_MAXNR))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TEGRA_THROUGHPUT_IOCTL_TARGET_FPS:
+ pr_debug("%s: TEGRA_THROUGHPUT_IOCTL_TARGET_FPS %lu\n",
+ __func__, arg);
+ err = throughput_set_target_fps(arg);
+ break;
+
+ default:
+ err = -ENOTTY;
+ }
+
+ return err;
+}
+
+static const struct file_operations throughput_user_fops = {
+ .owner = THIS_MODULE,
+ .open = throughput_open,
+ .release = throughput_release,
+ .unlocked_ioctl = throughput_ioctl,
+};
+
+#define TEGRA_THROUGHPUT_MINOR 1
+
+static struct miscdevice throughput_miscdev = {
+ .minor = TEGRA_THROUGHPUT_MINOR,
+ .name = "tegra-throughput",
+ .fops = &throughput_user_fops,
+ .mode = 0666,
+};
+
+int __init throughput_init_miscdev(void)
+{
+ int ret;
+
+ pr_debug("%s: initializing\n", __func__);
+
+ spin_lock_init(&lock);
+ INIT_WORK(&work, set_throughput_hint);
+
+ ret = misc_register(&throughput_miscdev);
+ if (ret) {
+ pr_err("can\'t reigster throughput miscdev"
+ " (minor %d err %d)\n", TEGRA_THROUGHPUT_MINOR, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+module_init(throughput_init_miscdev);
+
+void __exit throughput_exit_miscdev(void)
+{
+ pr_debug("%s: exiting\n", __func__);
+
+ cancel_work_sync(&work);
+
+ misc_deregister(&throughput_miscdev);
+}
+
+module_exit(throughput_exit_miscdev);
+
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 35f3df8810e0..f7528db8fd06 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2109,6 +2109,26 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
}
+int mmc_speed_class_control(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg)
+{
+ int err = -ENOSYS;
+ u32 status;
+
+ err = mmc_send_speed_class_ctrl(host, speed_class_ctrl_arg);
+ if (err)
+ return err;
+
+ /* Issue CMD13 to check for any errors during the busy period of CMD20 */
+ err = mmc_send_status(host->card, &status);
+ if (!err) {
+ if (status & R1_ERROR)
+ err = -EINVAL;
+ }
+ return err;
+}
+EXPORT_SYMBOL(mmc_speed_class_control);
+
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
@@ -2163,6 +2183,9 @@ int mmc_card_awake(struct mmc_host *host)
{
int err = -ENOSYS;
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ return 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
@@ -2178,6 +2201,9 @@ int mmc_card_sleep(struct mmc_host *host)
{
int err = -ENOSYS;
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ return 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 40c93b3dccd7..0e8001facac3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -976,13 +976,19 @@ static void mmc_detect(struct mmc_host *host)
*/
static int mmc_suspend(struct mmc_host *host)
{
+ int err;
+
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
- if (!mmc_host_is_spi(host))
+ if (mmc_card_can_sleep(host)) {
+ err = mmc_card_sleep(host);
+ if (!err)
+ mmc_card_set_sleep(host->card);
+ } else if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
- host->card->state &= ~MMC_STATE_HIGHSPEED;
+ host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_release_host(host);
return 0;
@@ -1002,7 +1008,11 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- err = mmc_init_card(host, host->ocr, host->card);
+ if (mmc_card_is_sleep(host->card)) {
+ err = mmc_card_awake(host);
+ mmc_card_clr_sleep(host->card);
+ } else
+ err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
@@ -1012,7 +1022,8 @@ static int mmc_power_restore(struct mmc_host *host)
{
int ret;
- host->card->state &= ~MMC_STATE_HIGHSPEED;
+ host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+ mmc_card_clr_sleep(host->card);
mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed153804..b06781e69ce3 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -389,3 +389,29 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
return 0;
}
+
+int mmc_send_speed_class_ctrl(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg)
+{
+ int err = 0;
+ struct mmc_command cmd = {
+ .opcode = SD_SPEED_CLASS_CONTROL,
+ .arg = (speed_class_ctrl_arg << 28),
+ .flags = MMC_RSP_R1B | MMC_CMD_AC | MMC_RSP_BUSY,
+ };
+
+ BUG_ON(!host);
+ BUG_ON(speed_class_ctrl_arg > 3);
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ return err;
+
+ /*
+ * If the host does not wait while the card signals busy, then we will
+ * will have to wait the max busy indication timeout.
+ */
+ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ mmc_delay(1000);
+ return err;
+}
+
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index ffc2305d905f..a77b8facceb4 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -20,6 +20,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
-
+int mmc_send_speed_class_ctrl(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg);
#endif
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index f5ea51bd0ed3..2f9d6f4f43e1 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
+CFLAGS_sdhci-tegra.o = -Werror
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 609fd6391d1f..8ff35e4cbfe4 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -74,7 +74,9 @@ static unsigned int tegra_sdhost_std_freq;
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock);
static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci);
+#endif
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
static unsigned int tegra3_sdhost_max_clk[4] = {
208000000, 104000000, 208000000, 104000000 };
#endif
@@ -227,7 +229,7 @@ static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci)
SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR50_SUPPORT;
sdhci_writew(sdhci, misc_ctrl, SDHCI_VENDOR_MISC_CNTRL);
}
-#endif
+#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */
static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
unsigned int uhs)
@@ -372,14 +374,7 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
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) ||
- (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50))) {
+ if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) {
/*
* In ddr mode, tegra sdmmc controller clock frequency
* should be double the card clock frequency.
@@ -394,6 +389,13 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
} else {
clk_rate = clock * 2;
}
+ } else if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) {
+ /*
+ * 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.
+ */
+ clk_rate = clock * 2;
} else {
if (clock <= tegra_sdhost_min_freq)
clk_rate = tegra_sdhost_min_freq;
@@ -410,7 +412,6 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
clk_set_rate(pltfm_host->clk, clk_rate);
sdhci->max_clk = clk_get_rate(pltfm_host->clk);
}
-
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock)
{
@@ -496,7 +497,7 @@ set_clk:
out:
sdhci->clock = clock;
}
-#endif
+#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */
static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
{
@@ -509,7 +510,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
if (clock) {
/* bring out sd instance from io dpd mode */
- tegra_io_dpd_disable(tegra_host->dpd);
+ if (tegra_host->dpd) {
+ mutex_lock(&tegra_host->dpd->delay_lock);
+ cancel_delayed_work_sync(&tegra_host->dpd->delay_dpd);
+ tegra_io_dpd_disable(tegra_host->dpd);
+ mutex_unlock(&tegra_host->dpd->delay_lock);
+ }
if (!tegra_host->clk_enabled) {
clk_enable(pltfm_host->clk);
@@ -530,7 +536,18 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
clk_disable(pltfm_host->clk);
tegra_host->clk_enabled = false;
/* io dpd enable call for sd instance */
- tegra_io_dpd_enable(tegra_host->dpd);
+
+ if (tegra_host->dpd) {
+ mutex_lock(&tegra_host->dpd->delay_lock);
+ if (tegra_host->dpd->need_delay_dpd) {
+ schedule_delayed_work(
+ &tegra_host->dpd->delay_dpd,
+ msecs_to_jiffies(100));
+ } else {
+ tegra_io_dpd_enable(tegra_host->dpd);
+ }
+ mutex_unlock(&tegra_host->dpd->delay_lock);
+ }
}
}
@@ -658,36 +675,15 @@ static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci,
sdhci_writel(sdhci, vendor_ctrl, SDHCI_VENDOR_CLOCK_CNTRL);
}
-static void sdhci_tegra_clear_set_irqs(struct sdhci_host *host,
- u32 clear, u32 set)
-{
- u32 ier;
-
- ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- ier &= ~clear;
- ier |= set;
- sdhci_writel(host, ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci)
{
int err = 0;
u8 ctrl;
- u32 ier;
u32 mask;
unsigned int timeout = 10;
int flags;
u32 intstatus;
- /*
- * As per the Host Controller spec v3.00, tuning command
- * generates Buffer Read Ready interrupt only, so enable that.
- */
- ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE);
- sdhci_tegra_clear_set_irqs(sdhci, ier, SDHCI_INT_DATA_AVAIL |
- SDHCI_INT_DATA_CRC);
-
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
while (sdhci_readl(sdhci, SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
@@ -759,7 +755,6 @@ static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci)
}
mdelay(1);
out:
- sdhci_tegra_clear_set_irqs(sdhci, SDHCI_INT_DATA_AVAIL, ier);
return err;
}
@@ -773,6 +768,7 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci)
unsigned int temp_pass_window = 0;
unsigned int best_low_pass_tap = 0;
unsigned int best_pass_window = 0;
+ u32 ier;
/* Tuning is valid only in SDR104 and SDR50 modes */
ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2);
@@ -785,11 +781,20 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci)
if (tap_delay_status == NULL) {
dev_err(mmc_dev(sdhci->mmc), "failed to allocate memory"
"for storing tap_delay_status\n");
- err = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
/*
+ * Disable all interrupts signalling.Enable interrupt status
+ * detection for buffer read ready and data crc. We use
+ * polling for tuning as it involves less overhead.
+ */
+ ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE);
+ sdhci_writel(sdhci, 0, SDHCI_SIGNAL_ENABLE);
+ sdhci_writel(sdhci, SDHCI_INT_DATA_AVAIL |
+ SDHCI_INT_DATA_CRC, SDHCI_INT_ENABLE);
+
+ /*
* Set each tap delay value and run frequency tuning. After each
* run, update the tap delay status as working or not working.
*/
@@ -840,7 +845,10 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci)
/* Run frequency tuning */
err = sdhci_tegra_run_frequency_tuning(sdhci);
-out:
+ /* Enable the normal interrupts signalling */
+ sdhci_writel(sdhci, ier, SDHCI_INT_ENABLE);
+ sdhci_writel(sdhci, ier, SDHCI_SIGNAL_ENABLE);
+
if (tap_delay_status)
kfree(tap_delay_status);
@@ -865,6 +873,12 @@ static int tegra_sdhci_suspend(struct sdhci_host *sdhci, pm_message_t state)
}
}
+ if (tegra_host->dpd) {
+ mutex_lock(&tegra_host->dpd->delay_lock);
+ tegra_host->dpd->need_delay_dpd = 1;
+ mutex_unlock(&tegra_host->dpd->delay_lock);
+ }
+
return 0;
}
@@ -905,9 +919,6 @@ static struct sdhci_ops tegra_sdhci_ops = {
.read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel,
.platform_8bit_width = tegra_sdhci_8bit,
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- .set_card_clock = tegra_3x_sdhci_set_card_clock,
-#endif
.set_clock = tegra_sdhci_set_clock,
.suspend = tegra_sdhci_suspend,
.resume = tegra_sdhci_resume,
@@ -981,7 +992,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate power gpio\n");
goto err_power_req;
}
- tegra_gpio_enable(plat->power_gpio);
gpio_direction_output(plat->power_gpio, 1);
}
@@ -992,7 +1002,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate cd gpio\n");
goto err_cd_req;
}
- tegra_gpio_enable(plat->cd_gpio);
gpio_direction_input(plat->cd_gpio);
tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0);
@@ -1027,7 +1036,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate wp gpio\n");
goto err_wp_req;
}
- tegra_gpio_enable(plat->wp_gpio);
gpio_direction_input(plat->wp_gpio);
}
@@ -1133,12 +1141,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
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)
- host->mmc->pm_flags |= MMC_PM_KEEP_POWER;
-#endif
-
tegra_sdhost_min_freq = TEGRA_SDHOST_MIN_FREQ;
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
tegra_host->hw_ops = &tegra_2x_sdhci_ops;
@@ -1160,23 +1162,17 @@ err_add_host:
err_clk_put:
clk_put(pltfm_host->clk);
err_clk_get:
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
err_wp_req:
if (gpio_is_valid(plat->cd_gpio))
free_irq(gpio_to_irq(plat->cd_gpio), host);
err_cd_irq_req:
- if (gpio_is_valid(plat->cd_gpio)) {
- tegra_gpio_disable(plat->cd_gpio);
+ if (gpio_is_valid(plat->cd_gpio))
gpio_free(plat->cd_gpio);
- }
err_cd_req:
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
err_power_req:
err_no_mem:
kfree(tegra_host);
@@ -1209,21 +1205,16 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
regulator_put(tegra_host->vdd_io_reg);
}
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
if (gpio_is_valid(plat->cd_gpio)) {
free_irq(gpio_to_irq(plat->cd_gpio), host);
- tegra_gpio_disable(plat->cd_gpio);
gpio_free(plat->cd_gpio);
}
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
if (tegra_host->clk_enabled)
clk_disable(pltfm_host->clk);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d3e9a4a4169f..aa03ca7d5226 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1852,19 +1852,15 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
int sdhci_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
+ u16 clk;
- if (!mmc->card)
+ if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
return 0;
if (mmc->ios.clock) {
- if (mmc->card->type != MMC_TYPE_SDIO) {
- if (host->ops->set_clock)
- host->ops->set_clock(host, mmc->ios.clock);
- sdhci_set_clock(host, mmc->ios.clock);
- } else {
- if (host->ops->set_card_clock)
- host->ops->set_card_clock(host, mmc->ios.clock);
- }
+ if (host->ops->set_clock)
+ host->ops->set_clock(host, mmc->ios.clock);
+ sdhci_set_clock(host, mmc->ios.clock);
}
return 0;
@@ -1873,19 +1869,14 @@ int sdhci_enable(struct mmc_host *mmc)
int sdhci_disable(struct mmc_host *mmc, int lazy)
{
struct sdhci_host *host = mmc_priv(mmc);
+ u16 clk;
- if (!mmc->card)
+ if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
return 0;
- /* For SDIO cards, only disable the card clock. */
- if (mmc->card->type != MMC_TYPE_SDIO) {
- sdhci_set_clock(host, 0);
- if (host->ops->set_clock)
- host->ops->set_clock(host, 0);
- } else {
- if (host->ops->set_card_clock)
- host->ops->set_card_clock(host, 0);
- }
+ sdhci_set_clock(host, 0);
+ if (host->ops->set_clock)
+ host->ops->set_clock(host, 0);
return 0;
}
@@ -2348,6 +2339,15 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
}
if (mmc->card) {
+ /*
+ * If eMMC cards are put in sleep state, Vccq can be disabled
+ * but Vcc would still be powered on. In resume, we only restore
+ * the controller context. So, set MMC_PM_KEEP_POWER flag.
+ */
+ if (mmc_card_can_sleep(mmc) &&
+ !(mmc->caps & MMC_CAP2_NO_SLEEP_CMD))
+ mmc->pm_flags = MMC_PM_KEEP_POWER;
+
ret = mmc_suspend_host(host->mmc);
if (ret) {
if (has_tuning_timer) {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index bf48767e0ef2..c00833de19da 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -260,7 +260,6 @@ struct sdhci_ops {
#endif
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
- void (*set_card_clock)(struct sdhci_host *host, unsigned int clock);
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 67345a00a5ab..b9337a4f0c06 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -18,4 +18,5 @@ obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
obj-$(CONFIG_MTD_M25P80) += m25p80.o
obj-$(CONFIG_MTD_SST25L) += sst25l.o
+CFLAGS_tegra_nand.o = -Werror
obj-$(CONFIG_MTD_NAND_TEGRA) += tegra_nand.o
diff --git a/drivers/mtd/devices/tegra_nand.c b/drivers/mtd/devices/tegra_nand.c
index 92cd70f2fd46..6034f0b2f239 100644
--- a/drivers/mtd/devices/tegra_nand.c
+++ b/drivers/mtd/devices/tegra_nand.c
@@ -1654,7 +1654,6 @@ static int __devinit tegra_nand_probe(struct platform_device *pdev)
if (plat->wp_gpio) {
gpio_request(plat->wp_gpio, "nand_wp");
- tegra_gpio_enable(plat->wp_gpio);
gpio_direction_output(plat->wp_gpio, 1);
}
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index bb5eef14a367..dbc68e0e87cb 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -60,4 +60,5 @@ obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
+CFLAGS_tegra_nor.o = -Werror
obj-$(CONFIG_MTD_NOR_TEGRA) += tegra_nor.o
diff --git a/drivers/mtd/maps/tegra_nor.c b/drivers/mtd/maps/tegra_nor.c
index 505a2591f884..41adb1e40382 100644
--- a/drivers/mtd/maps/tegra_nor.c
+++ b/drivers/mtd/maps/tegra_nor.c
@@ -1,9 +1,5 @@
/*
- * drivers/mtd/maps/tegra_nor.c
- *
- * MTD mapping driver for the internal SNOR controller in Tegra SoCs
- *
- * Copyright (C) 2009 - 2012 NVIDIA Corporation
+ * Copyright (C) 2009-2012, NVIDIA Corporation. All rights reserved.
*
* Author:
* Raghavendra VK <rvk@nvidia.com>
@@ -21,6 +17,11 @@
* 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.
+ *
+ * drivers/mtd/maps/tegra_nor.c
+ *
+ * MTD mapping driver for the internal SNOR controller in Tegra SoCs
+ *
*/
#include <linux/platform_device.h>
@@ -139,7 +140,7 @@ static inline void snor_tegra_writel(struct tegra_nor_info *tnor,
#define DRV_NAME "tegra-nor"
-static const char * const part_probes[] = { "cmdlinepart", NULL };
+static const char *part_probes[] = { "cmdlinepart", NULL };
static int wait_for_dma_completion(struct tegra_nor_info *info)
{
@@ -160,6 +161,7 @@ static void tegra_flash_dma(struct map_info *map,
u32 copy_to = (u32)to;
struct tegra_nor_info *c =
container_of(map, struct tegra_nor_info, map);
+ struct tegra_nor_chip_parms *chip_parm = &c->plat->chip_parms;
unsigned int bytes_remaining = len;
snor_config = c->init_config;
@@ -174,9 +176,52 @@ static void tegra_flash_dma(struct map_info *map,
* controller register only after all parameters are set.
*/
/* SNOR CONFIGURATION SETUP */
- snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(1);
- /* 8 word page */
- snor_config |= TEGRA_SNOR_CONFIG_PAGE_SZ(2);
+ switch(chip_parm->ReadMode)
+ {
+ case NorReadMode_Async:
+ snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0);
+ break;
+
+ case NorReadMode_Page:
+ switch(chip_parm->PageLength)
+ {
+ case NorPageLength_Unsupported :
+ snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(0);
+ break;
+
+ case NorPageLength_4Word :
+ snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(1);
+ snor_config |= TEGRA_SNOR_CONFIG_PAGE_SZ(1);
+ break;
+
+ case NorPageLength_8Word :
+ snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(1);
+ snor_config |= TEGRA_SNOR_CONFIG_PAGE_SZ(2);
+ break;
+ }
+ break;
+
+ case NorReadMode_Burst:
+ snor_config |= TEGRA_SNOR_CONFIG_DEVICE_MODE(2);
+ switch(chip_parm->BurstLength)
+ {
+ case NorBurstLength_CntBurst :
+ snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(0);
+ break;
+ case NorBurstLength_8Word :
+ snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(1);
+ break;
+
+ case NorBurstLength_16Word :
+ snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(2);
+ break;
+
+ case NorBurstLength_32Word :
+ snor_config |= TEGRA_SNOR_CONFIG_BURST_LEN(3);
+ break;
+ }
+ break;
+ }
snor_config |= TEGRA_SNOR_CONFIG_MST_ENB;
/* SNOR DMA CONFIGURATION SETUP */
/* NOR -> AHB */
@@ -273,8 +318,28 @@ static int tegra_snor_controller_init(struct tegra_nor_info *info)
default:
return -EINVAL;
}
- config |= TEGRA_SNOR_CONFIG_BURST_LEN(0);
- config &= ~TEGRA_SNOR_CONFIG_MUX_MODE;
+ switch (chip_parm->MuxMode)
+ {
+ case NorMuxMode_ADNonMux:
+ config &= ~TEGRA_SNOR_CONFIG_MUX_MODE;
+ break;
+ case NorMuxMode_ADMux:
+ config |= TEGRA_SNOR_CONFIG_MUX_MODE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (chip_parm->ReadyActive)
+ {
+ case NorReadyActive_WithData:
+ config &= ~TEGRA_SNOR_CONFIG_RDY_ACTIVE;
+ break;
+ case NorReadyActive_BeforeData:
+ config |= TEGRA_SNOR_CONFIG_RDY_ACTIVE;
+ break;
+ default:
+ return -EINVAL;
+ }
snor_tegra_writel(info, config, TEGRA_SNOR_CONFIG_REG);
info->init_config = config;
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index f30752565b33..5f85fe79c595 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -15,5 +15,6 @@ obj-$(CONFIG_CAIF_SHM) += caif_shm.o
obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
# Tegra specific SPI slave physical interfaces module
+CFLAGS_tegra_caif_sspi.o = -Werror
tegra_cfspi_slave-objs := tegra_caif_sspi.o
obj-$(CONFIG_TEGRA_SPI_CAIF) += tegra_cfspi_slave.o
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index c31b1185f492..14bda2ecabde 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -604,6 +604,14 @@ static const struct usb_device_id products [] = {
USB_DEVICE(0x0489,0xE03A),
.driver_info = (unsigned long)&rmnet_info,
},
+
+/* ZM5250 */
+{
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+ | USB_DEVICE_ID_MATCH_DEVICE,
+ USB_DEVICE(0x19D2,0x1554),
+ .driver_info = (unsigned long)&rmnet_info,
+},
/*
* WHITELIST!!!
*
diff --git a/drivers/net/usb/raw_ip_net.c b/drivers/net/usb/raw_ip_net.c
index 1b3b89b3c274..dc9b5e61fd9e 100644
--- a/drivers/net/usb/raw_ip_net.c
+++ b/drivers/net/usb/raw_ip_net.c
@@ -3,7 +3,7 @@
*
* USB network driver for RAW-IP modems.
*
- * 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
@@ -42,25 +42,24 @@
#endif /* USB_NET_BUFSIZ */
/* maximum interface number supported */
-#define MAX_INTFS 3
+#define MAX_INTFS 5
MODULE_LICENSE("GPL");
-int g_i;
+static int g_i;
-int max_intfs = MAX_INTFS;
-unsigned long usb_net_raw_ip_vid = 0x1519;
-unsigned long usb_net_raw_ip_pid = 0x0020;
-unsigned long usb_net_raw_ip_intf[MAX_INTFS] = { 0x03, 0x05, 0x07 };
+/* To support more rmnet interfaces, increase the default max_intfs or
+ * pass kernel module parameter.
+ * e.g. insmod raw_ip_net.ko max_intfs=5
+ */
+static int max_intfs = 2; /* default number of interfaces */
+
+static unsigned long usb_net_raw_ip_intf[MAX_INTFS] = { 3, 5, 9, 11, 13};
unsigned long usb_net_raw_ip_rx_debug;
unsigned long usb_net_raw_ip_tx_debug;
module_param(max_intfs, int, 0644);
MODULE_PARM_DESC(max_intfs, "usb net (raw-ip) - max. interfaces supported");
-module_param(usb_net_raw_ip_vid, ulong, 0644);
-MODULE_PARM_DESC(usb_net_raw_ip_vid, "usb net (raw-ip) - USB VID");
-module_param(usb_net_raw_ip_pid, ulong, 0644);
-MODULE_PARM_DESC(usb_net_raw_ip_pid, "usb net (raw-ip) - USB PID");
module_param(usb_net_raw_ip_rx_debug, ulong, 0644);
MODULE_PARM_DESC(usb_net_raw_ip_rx_debug, "usb net (raw-ip) - rx debug");
module_param(usb_net_raw_ip_tx_debug, ulong, 0644);
@@ -99,11 +98,10 @@ struct baseband_usb {
int susp_count;
};
-static struct baseband_usb *baseband_usb_net[MAX_INTFS] = { 0, 0, 0};
+static struct baseband_usb *baseband_usb_net[MAX_INTFS] = { 0, 0, 0, 0, 0};
-static struct net_device *usb_net_raw_ip_dev[MAX_INTFS] = { 0, 0, 0};
+static struct net_device *usb_net_raw_ip_dev[MAX_INTFS] = { 0, 0, 0, 0, 0};
-static unsigned int g_usb_interface_index[MAX_INTFS];
static struct usb_interface *g_usb_interface[MAX_INTFS];
static int usb_net_raw_ip_rx_urb_submit(struct baseband_usb *usb);
@@ -117,7 +115,7 @@ static void usb_net_raw_ip_tx_urb_comp(struct urb *urb);
static int baseband_usb_driver_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- int i = g_i;
+ int i = g_i, j;
pr_debug("%s(%d) { intf %p id %p\n", __func__, __LINE__, intf, id);
@@ -138,16 +136,18 @@ static int baseband_usb_driver_probe(struct usb_interface *intf,
pr_debug("intf->cur_altsetting->desc.iInterface %02x\n",
intf->cur_altsetting->desc.iInterface);
- if (g_usb_interface_index[i] !=
- intf->cur_altsetting->desc.bInterfaceNumber) {
- pr_debug("%s(%d) } -ENODEV\n", __func__, __LINE__);
- return -ENODEV;
- } else {
- g_usb_interface[i] = intf;
+ /* register interfaces that are assigned to raw-ip */
+ for (j = 0; j < max_intfs; j++) {
+ if (usb_net_raw_ip_intf[j] ==
+ intf->cur_altsetting->desc.bInterfaceNumber) {
+ pr_info("%s: raw_ip using interface %d\n", __func__,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+ g_usb_interface[j] = intf;
+ return 0;
+ }
}
-
pr_debug("%s(%d) }\n", __func__, __LINE__);
- return 0;
+ return -ENODEV;
}
static void baseband_usb_driver_disconnect(struct usb_interface *intf)
@@ -350,49 +350,27 @@ static int baseband_usb_driver_reset_resume(struct usb_interface *intf)
}
#endif /* CONFIG_PM */
-static struct usb_device_id baseband_usb_driver_id_table[MAX_INTFS][2];
-
-static char baseband_usb_driver_name[MAX_INTFS][32];
+static struct usb_device_id baseband_usb_driver_id_table[] = {
+ /* xmm modem vid, pid */
+ { USB_DEVICE(0x1519, 0x0020), },
+ { },
+};
-static struct usb_driver baseband_usb_driver[MAX_INTFS] = {
- {
- .name = baseband_usb_driver_name[0],
- .probe = baseband_usb_driver_probe,
- .disconnect = baseband_usb_driver_disconnect,
- .id_table = baseband_usb_driver_id_table[0],
-#ifdef CONFIG_PM
- .suspend = baseband_usb_driver_suspend,
- .resume = baseband_usb_driver_resume,
- .reset_resume = baseband_usb_driver_reset_resume,
- .supports_autosuspend = 1,
-#endif
- },
- {
- .name = baseband_usb_driver_name[1],
+static struct usb_driver baseband_usb_driver = {
+ .name = "bb_raw_ip_net",
.probe = baseband_usb_driver_probe,
.disconnect = baseband_usb_driver_disconnect,
- .id_table = baseband_usb_driver_id_table[1],
+ .id_table = baseband_usb_driver_id_table,
#ifdef CONFIG_PM
.suspend = baseband_usb_driver_suspend,
.resume = baseband_usb_driver_resume,
.reset_resume = baseband_usb_driver_reset_resume,
.supports_autosuspend = 1,
#endif
- },
- {
- .name = baseband_usb_driver_name[2],
- .probe = baseband_usb_driver_probe,
- .disconnect = baseband_usb_driver_disconnect,
- .id_table = baseband_usb_driver_id_table[2],
-#ifdef CONFIG_PM
- .suspend = baseband_usb_driver_suspend,
- .resume = baseband_usb_driver_resume,
- .reset_resume = baseband_usb_driver_reset_resume,
- .supports_autosuspend = 1,
-#endif
- },
};
+MODULE_DEVICE_TABLE(usb, baseband_usb_driver_id_table);
+
static void find_usb_pipe(struct baseband_usb *usb)
{
struct usb_device *usbdev = usb->usb.device;
@@ -434,13 +412,10 @@ static void find_usb_pipe(struct baseband_usb *usb)
void baseband_usb_close(struct baseband_usb *usb);
-struct baseband_usb *baseband_usb_open(int index,
- unsigned int vid,
- unsigned int pid,
- unsigned int intf)
+struct baseband_usb *baseband_usb_open(int index, unsigned int intf)
{
struct baseband_usb *usb;
- int err;
+ int i;
pr_debug("baseband_usb_open {\n");
@@ -453,37 +428,25 @@ struct baseband_usb *baseband_usb_open(int index,
/* create semaphores */
sema_init(&usb->sem, 1);
- /* open usb driver */
- sprintf(baseband_usb_driver_name[index],
- "baseband_usb_%x_%x_%x",
- vid, pid, intf);
- baseband_usb_driver_id_table[index][0].match_flags =
- USB_DEVICE_ID_MATCH_DEVICE;
- baseband_usb_driver_id_table[index][0].idVendor = vid;
- baseband_usb_driver_id_table[index][0].idProduct = pid;
- g_usb_interface_index[index] = intf;
- g_usb_interface[index] = (struct usb_interface *) 0;
- err = usb_register(&baseband_usb_driver[index]);
- if (err < 0) {
- pr_err("cannot open usb driver - err %d\n", err);
- kfree(usb);
- return (struct baseband_usb *) 0;
- }
+ /* open usb interface */
usb->baseband_index = index;
- usb->usb.driver = &baseband_usb_driver[index];
+ usb->usb.driver = &baseband_usb_driver;
if (!g_usb_interface[index]) {
- pr_err("cannot open usb driver - !g_usb_interface[%d]\n",
- index);
- usb_deregister(usb->usb.driver);
- kfree(usb);
- return (struct baseband_usb *) 0;
+ /* wait for usb probe */
+ for (i = 0; i < 50; i++)
+ if (!g_usb_interface[index])
+ msleep(20);
+ if (!g_usb_interface[index]) {
+ pr_err("can't open usb: !g_usb_interface[%d]\n", index);
+ kfree(usb);
+ return NULL;
+ }
}
usb->usb.device = interface_to_usbdev(g_usb_interface[index]);
usb->usb.interface = g_usb_interface[index];
find_usb_pipe(usb);
usb->usb.rx_urb = (struct urb *) 0;
usb->usb.tx_urb = (struct urb *) 0;
- g_usb_interface_index[index] = ~0U;
g_usb_interface[index] = (struct usb_interface *) 0;
pr_debug("usb->usb.driver->name %s\n", usb->usb.driver->name);
pr_debug("usb->usb.device %p\n", usb->usb.device);
@@ -509,12 +472,7 @@ void baseband_usb_close(struct baseband_usb *usb)
return;
/* close usb driver */
- if (usb->usb.driver) {
- pr_debug("close usb driver {\n");
- usb_deregister(usb->usb.driver);
- usb->usb.driver = (struct usb_driver *) 0;
- pr_debug("close usb driver }\n");
- }
+ usb->usb.driver = (struct usb_driver *) 0;
/* destroy semaphores */
memset(&usb->sem, 0, sizeof(usb->sem));
@@ -746,10 +704,28 @@ static void usb_net_raw_ip_rx_urb_comp(struct urb *urb)
skb_reserve(skb, NET_IP_ALIGN);
dst = skb_put(skb, 14);
memcpy(dst, ethernet_header, 14);
+ if ((((unsigned char *) urb->transfer_buffer)[0]
+ & 0xf0) == 0x60) {
+ /* ipv6 ether type */
+ dst[12] = 0x86;
+ dst[13] = 0xdd;
+ }
dst = skb_put(skb, urb->actual_length);
memcpy(dst, urb->transfer_buffer, urb->actual_length);
skb->protocol = eth_type_trans(skb,
usb_net_raw_ip_dev[i]);
+ pr_debug("%s: ntohs(skb->protocol) %04x (%s)\n",
+ __func__, ntohs(skb->protocol),
+ (ntohs(skb->protocol) == 0x0800)
+ ? "IPv4"
+ : (ntohs(skb->protocol) == 0x86dd)
+ ? "IPv6"
+ : "unknown");
+ pr_debug("%s: %02x %02x %02x %02x\n", __func__,
+ ((unsigned char *)urb->transfer_buffer)[0],
+ ((unsigned char *)urb->transfer_buffer)[1],
+ ((unsigned char *)urb->transfer_buffer)[2],
+ ((unsigned char *)urb->transfer_buffer)[3]);
/* pass skb to network stack */
if (netif_rx(skb) < 0) {
pr_err("usb_net_raw_ip_rx_urb_comp_work - "
@@ -892,6 +868,18 @@ static int usb_net_raw_ip_tx_urb_submit(struct baseband_usb *usb,
usb_net_raw_ip_tx_urb_comp,
usb);
urb->transfer_flags = URB_ZERO_PACKET;
+ pr_debug("%s: ntohs(skb->protocol) %04x (%s)\n",
+ __func__, ntohs(skb->protocol),
+ (ntohs(skb->protocol) == 0x0800)
+ ? "IPv4"
+ : (ntohs(skb->protocol) == 0x86dd)
+ ? "IPv6"
+ : "unknown");
+ pr_debug("%s: %02x %02x %02x %02x\n", __func__,
+ ((unsigned char *)urb->transfer_buffer)[0],
+ ((unsigned char *)urb->transfer_buffer)[1],
+ ((unsigned char *)urb->transfer_buffer)[2],
+ ((unsigned char *)urb->transfer_buffer)[3]);
/* queue tx urb work */
usb_anchor_urb(urb, &usb->usb.tx_urb_deferred);
@@ -923,8 +911,8 @@ static void usb_net_raw_ip_tx_urb_work(struct work_struct *work)
/* check if usb interface disconnected */
if (!usb->usb.interface) {
- pr_err("%s: not submitting tx urb %p -interface disconnected\n",
- __func__, urb);
+ pr_err("%s: not submitting tx urb -interface disconnected\n",
+ __func__);
return;
}
@@ -1044,12 +1032,18 @@ static int usb_net_raw_ip_init(void)
pr_debug("usb_net_raw_ip_init {\n");
+ err = usb_register(&baseband_usb_driver);
+ if (err < 0) {
+ pr_err("cannot open usb driver - err %d\n", err);
+ return err;
+ }
+
/* create multiple raw-ip network devices */
for (i = 0; i < max_intfs; i++) {
/* open baseband usb */
g_i = i;
- baseband_usb_net[i] = baseband_usb_open(i, usb_net_raw_ip_vid,
- usb_net_raw_ip_pid, usb_net_raw_ip_intf[i]);
+ baseband_usb_net[i] = baseband_usb_open(i,
+ usb_net_raw_ip_intf[i]);
if (!baseband_usb_net[i]) {
pr_err("cannot open baseband usb net\n");
err = -1;
@@ -1138,6 +1132,7 @@ error_exit:
baseband_usb_net[i] = (struct baseband_usb *) 0;
}
}
+ usb_deregister(&baseband_usb_driver);
return err;
}
@@ -1183,6 +1178,10 @@ static void usb_net_raw_ip_exit(void)
}
}
+ pr_debug("close usb driver {\n");
+ usb_deregister(&baseband_usb_driver);
+ pr_debug("close usb driver }\n");
+
pr_debug("usb_net_raw_ip_exit }\n");
}
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 82965e20e076..930a4c1959d2 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -210,6 +210,7 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf)
} else {
usb_fill_int_urb(dev->interrupt, dev->udev, pipe,
buf, maxp, intr_complete, dev, period);
+ dev->interrupt->transfer_flags |= URB_FREE_BUFFER;
dev_dbg(&intf->dev,
"status ep%din, %d bytes period %d\n",
usb_pipeendpoint(pipe), maxp, period);
@@ -277,17 +278,32 @@ int usbnet_change_mtu (struct net_device *net, int new_mtu)
}
EXPORT_SYMBOL_GPL(usbnet_change_mtu);
+/* The caller must hold list->lock */
+static void __usbnet_queue_skb(struct sk_buff_head *list,
+ struct sk_buff *newsk, enum skb_state state)
+{
+ struct skb_data *entry = (struct skb_data *) newsk->cb;
+
+ __skb_queue_tail(list, newsk);
+ entry->state = state;
+}
+
/*-------------------------------------------------------------------------*/
/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from
* completion callbacks. 2.5 should have fixed those bugs...
*/
-static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_head *list)
+static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb,
+ struct sk_buff_head *list, enum skb_state state)
{
unsigned long flags;
+ enum skb_state old_state;
+ struct skb_data *entry = (struct skb_data *) skb->cb;
spin_lock_irqsave(&list->lock, flags);
+ old_state = entry->state;
+ entry->state = state;
__skb_unlink(skb, list);
spin_unlock(&list->lock);
spin_lock(&dev->done.lock);
@@ -295,6 +311,7 @@ static void defer_bh(struct usbnet *dev, struct sk_buff *skb, struct sk_buff_hea
if (dev->done.qlen == 1)
tasklet_schedule(&dev->bh);
spin_unlock_irqrestore(&dev->done.lock, flags);
+ return old_state;
}
/* some work can't be done in tasklets, so we use keventd
@@ -324,18 +341,17 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
unsigned long lockflags;
size_t size = dev->rx_urb_size;
- if ((skb = alloc_skb (size + NET_IP_ALIGN, flags)) == NULL) {
+ skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
+ if (!skb) {
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
usb_free_urb (urb);
return -ENOMEM;
}
- skb_reserve (skb, NET_IP_ALIGN);
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
entry->dev = dev;
- entry->state = rx_start;
entry->length = 0;
usb_fill_bulk_urb (urb, dev->udev, dev->in,
@@ -367,7 +383,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
tasklet_schedule (&dev->bh);
break;
case 0:
- __skb_queue_tail (&dev->rxq, skb);
+ __usbnet_queue_skb(&dev->rxq, skb, rx_start);
}
} else {
netif_dbg(dev, ifdown, dev->net, "rx: stopped\n");
@@ -418,16 +434,17 @@ static void rx_complete (struct urb *urb)
struct skb_data *entry = (struct skb_data *) skb->cb;
struct usbnet *dev = entry->dev;
int urb_status = urb->status;
+ enum skb_state state;
skb_put (skb, urb->actual_length);
- entry->state = rx_done;
+ state = rx_done;
entry->urb = NULL;
switch (urb_status) {
/* success */
case 0:
if (skb->len < dev->net->hard_header_len) {
- entry->state = rx_cleanup;
+ state = rx_cleanup;
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
netif_dbg(dev, rx_err, dev->net,
@@ -466,7 +483,7 @@ static void rx_complete (struct urb *urb)
"rx throttle %d\n", urb_status);
}
block:
- entry->state = rx_cleanup;
+ state = rx_cleanup;
entry->urb = urb;
urb = NULL;
break;
@@ -477,18 +494,20 @@ block:
// FALLTHROUGH
default:
- entry->state = rx_cleanup;
+ state = rx_cleanup;
dev->net->stats.rx_errors++;
netif_dbg(dev, rx_err, dev->net, "rx status %d\n", urb_status);
break;
}
- defer_bh(dev, skb, &dev->rxq);
+ state = defer_bh(dev, skb, &dev->rxq, state);
if (urb) {
if (netif_running (dev->net) &&
- !test_bit (EVENT_RX_HALT, &dev->flags)) {
+ !test_bit (EVENT_RX_HALT, &dev->flags) &&
+ state != unlink_start) {
rx_submit (dev, urb, GFP_ATOMIC);
+ usb_mark_last_busy(dev->udev);
return;
}
usb_free_urb (urb);
@@ -573,18 +592,34 @@ EXPORT_SYMBOL_GPL(usbnet_purge_paused_rxq);
static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
{
unsigned long flags;
- struct sk_buff *skb, *skbnext;
+ struct sk_buff *skb;
int count = 0;
spin_lock_irqsave (&q->lock, flags);
- skb_queue_walk_safe(q, skb, skbnext) {
+ while (!skb_queue_empty(q)) {
struct skb_data *entry;
struct urb *urb;
int retval;
- entry = (struct skb_data *) skb->cb;
+ skb_queue_walk(q, skb) {
+ entry = (struct skb_data *) skb->cb;
+ if (entry->state != unlink_start)
+ goto found;
+ }
+ break;
+found:
+ entry->state = unlink_start;
urb = entry->urb;
+ /*
+ * Get reference count of the URB to avoid it to be
+ * freed during usb_unlink_urb, which may trigger
+ * use-after-free problem inside usb_unlink_urb since
+ * usb_unlink_urb is always racing with .complete
+ * handler(include defer_bh).
+ */
+ usb_get_urb(urb);
+ spin_unlock_irqrestore(&q->lock, flags);
// during some PM-driven resume scenarios,
// these (async) unlinks complete immediately
retval = usb_unlink_urb (urb);
@@ -592,6 +627,8 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
else
count++;
+ usb_put_urb(urb);
+ spin_lock_irqsave(&q->lock, flags);
}
spin_unlock_irqrestore (&q->lock, flags);
return count;
@@ -1022,9 +1059,7 @@ static void tx_complete (struct urb *urb)
}
usb_autopm_put_interface_async(dev->intf);
- urb->dev = NULL;
- entry->state = tx_done;
- defer_bh(dev, skb, &dev->txq);
+ (void) defer_bh(dev, skb, &dev->txq, tx_done);
}
/*-------------------------------------------------------------------------*/
@@ -1077,7 +1112,6 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
entry->dev = dev;
- entry->state = tx_start;
entry->length = length;
usb_fill_bulk_urb (urb, dev->udev, dev->out,
@@ -1136,7 +1170,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
break;
case 0:
net->trans_start = jiffies;
- __skb_queue_tail (&dev->txq, skb);
+ __usbnet_queue_skb(&dev->txq, skb, tx_start);
if (dev->txq.qlen >= TX_QLEN (dev))
netif_stop_queue (net);
}
@@ -1531,7 +1565,7 @@ int usbnet_resume (struct usb_interface *intf)
if (test_bit(EVENT_DEV_OPEN, &dev->flags)) {
if (!(dev->txq.qlen >= TX_QLEN(dev)))
- netif_start_queue(dev->net);
+ netif_tx_wake_all_queues(dev->net);
tasklet_schedule (&dev->bh);
}
}
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig
index ef9ce5a00538..b02a173f98a5 100644
--- a/drivers/net/wireless/bcmdhd/Kconfig
+++ b/drivers/net/wireless/bcmdhd/Kconfig
@@ -26,6 +26,7 @@ config BCMDHD_NVRAM_DIR
config BCMDHD_WEXT
bool "Enable WEXT support"
+ depends on BCMDHD
select WIRELESS_EXT
select WEXT_PRIV
help
@@ -54,15 +55,11 @@ config DHD_ENABLE_P2P
config BCMDHD_CFG80211
bool "Enable CFG80211 support"
- depends on CFG80211
+ depends on BCMDHD && CFG80211
+ default n
help
Enables CFG80211 support
-config BCMDHD_NOAPI
- bool "No wireless API"
- help
- No wireless API is needed
-
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 2851388cf194..4ec987da11f8 100644
--- a/drivers/net/wireless/bcmdhd/Makefile
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -8,9 +8,15 @@ 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
+# Only for JB (disable on ICS)
+DHDCFLAGS += -DSET_RANDOM_MAC_SOFTAP -DWL_CFG80211_STA_EVENT
+
+# for WFD IE support
+DHDCFLAGS += -DWLWFDIE
+
+
ifeq ($(CONFIG_BCMDHD_WIFI_CONTROL_FUNC),y)
DHDCFLAGS += -DCONFIG_WIFI_CONTROL_FUNC
else
@@ -38,7 +44,7 @@ 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 dhd_cfg80211.o
+ bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o
obj-$(CONFIG_BCMDHD) += bcmdhd.o
bcmdhd-objs += $(DHDOFILES)
@@ -48,17 +54,21 @@ bcmdhd-objs += wl_iw.o
DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT
endif
-ifneq ($(CONFIG_CFG80211),)
-bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o
+ifneq ($(CONFIG_BCMDHD_CFG80211),)
+bcmdhd-objs += wl_cfg80211.o dhd_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
endif
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
index 6a25d9a5a57f..84ab7564ad7d 100644
--- a/drivers/net/wireless/bcmdhd/bcmevent.c
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -54,7 +54,6 @@ const bcmevent_name_t bcmevent_names[] = {
{ WLC_E_MIC_ERROR, "MIC_ERROR" },
{ WLC_E_NDIS_LINK, "NDIS_LINK" },
{ WLC_E_ROAM, "ROAM" },
- { WLC_E_TXFAIL, "TXFAIL" },
{ WLC_E_PMKID_CACHE, "PMKID_CACHE" },
{ WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF" },
{ WLC_E_PRUNE, "PRUNE" },
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
index e67eeca1f99c..ffcb49bda290 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -36,6 +36,7 @@
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
@@ -1326,7 +1327,7 @@ 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 = mmc_power_restore_host((gInstance->func[0])->card->host))) {
sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
return ret;
}
@@ -1405,6 +1406,8 @@ sdioh_stop(sdioh_info_t *si)
#endif
bcmsdh_oob_intr_set(FALSE);
#endif /* !defined(OOB_INTR_ONLY) */
+ if (mmc_power_save_host((gInstance->func[0])->card->host))
+ sd_err(("%s card power save fail\n", __FUNCTION__));
}
else
sd_err(("%s Failed\n", __FUNCTION__));
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
index 656953939b71..6ca85311b4c4 100644
--- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -34,6 +34,7 @@
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
@@ -131,6 +132,10 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func,
#endif
sd_trace(("F2 found, calling bcmsdh_probe_bcmdhd...\n"));
ret = bcmsdh_probe_bcmdhd(&func->dev);
+#ifndef DHDTHREAD
+ if (mmc_power_save_host(func->card->host))
+ sd_err(("%s: card power save fail", __FUNCTION__));
+#endif
}
return ret;
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
index 5ff5c218ddcf..871c2bfb51d2 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 328934 2012-04-23 05:15:42Z $
+ * $Id: dhd.h 333052 2012-05-12 02:09:28Z $
*/
/****************
@@ -437,10 +437,14 @@ 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_set_ex(dhd_pub_t *dhd, wl_pfn_t* ssidnet, int nssid,
+ ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time);
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_set_ex(struct net_device *dev, wl_pfn_t* ssidnet, int nssid,
+ ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time);
extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
extern int dhd_dev_get_pno_status(struct net_device *dev);
#endif /* PNO_SUPPORT */
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
index d9810ace1cb4..3ccc55d87d4b 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 329682 2012-04-26 09:20:38Z $
+ * $Id: dhd_common.c 331276 2012-05-04 08:05:57Z $
*/
#include <typedefs.h>
#include <osl.h>
@@ -1890,12 +1890,13 @@ dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
return ret;
}
- if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
- return (ret);
memset(iovbuf, 0, sizeof(iovbuf));
#ifndef WL_SCHED_SCAN
+ if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
+ return (ret);
+
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;
@@ -1939,9 +1940,10 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
err = -1;
return err;
}
-
+#ifndef WL_SCHED_SCAN
if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
return (err);
+#endif /* !WL_SCHED_SCAN */
/* Check for broadcast ssid */
for (k = 0; k < nssid; k++) {
@@ -2035,6 +2037,123 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
}
int
+dhd_pno_set_ex(dhd_pub_t *dhd, wl_pfn_t* ssidnet, int nssid, ushort pno_interval,
+ int pno_repeat, int pno_expo_max, int pno_lost_time)
+{
+ int err = -1;
+ char iovbuf[128];
+ int k, i;
+ wl_pfn_param_t pfn_param;
+ wl_pfn_t pfn_element;
+ uint len = 0;
+
+ DHD_TRACE(("%s nssid=%d pno_interval=%d\n", __FUNCTION__, nssid, pno_interval));
+
+ if ((!dhd) && (!ssidnet)) {
+ DHD_ERROR(("%s error exit\n", __FUNCTION__));
+ err = -1;
+ return err;
+ }
+
+ if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
+ return (err);
+
+ /* Check for broadcast ssid */
+ for (k = 0; k < nssid; k++) {
+ if (!ssidnet[k].ssid.SSID_len) {
+ DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
+ return err;
+ }
+ }
+/* #define PNO_DUMP 1 */
+#ifdef PNO_DUMP
+ {
+ int j;
+ for (j = 0; j < nssid; j++) {
+ DHD_ERROR(("%d: scan for %s size =%d\n", j,
+ ssidnet[j].ssid.SSID, ssidnet[j].ssid.SSID_len));
+ }
+ }
+#endif /* PNO_DUMP */
+
+ /* clean up everything */
+ if ((err = dhd_pno_clean(dhd)) < 0) {
+ DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
+ return err;
+ }
+ memset(iovbuf, 0, sizeof(iovbuf));
+ memset(&pfn_param, 0, sizeof(pfn_param));
+ memset(&pfn_element, 0, sizeof(pfn_element));
+
+ /* set pfn parameters */
+ pfn_param.version = htod32(PFN_VERSION);
+ pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
+
+ /* check and set extra pno params */
+ if ((pno_repeat != 0) || (pno_expo_max != 0)) {
+ pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
+ pfn_param.repeat = (uchar) (pno_repeat);
+ pfn_param.exp = (uchar) (pno_expo_max);
+ }
+
+ /* set up pno scan fr */
+ if (pno_interval != 0)
+ pfn_param.scan_freq = htod32(pno_interval);
+
+ if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) {
+ DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC));
+ return err;
+ }
+ if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) {
+ DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
+ return err;
+ }
+
+ /* network lost time */
+ pfn_param.lost_network_timeout = htod32(pno_lost_time);
+
+ len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
+ if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s pfn_set failed for error=%d\n",
+ __FUNCTION__, err));
+ return err;
+ } else {
+ DHD_TRACE(("%s pfn_set OK with PNO time=%d repeat=%d max_adjust=%d\n",
+ __FUNCTION__, pfn_param.scan_freq,
+ pfn_param.repeat, pfn_param.exp));
+ }
+
+ /* set all pfn ssid */
+ for (i = 0; i < nssid; i++) {
+ pfn_element.flags = htod32(ssidnet[i].flags);
+ pfn_element.infra = htod32(ssidnet[i].infra);
+ pfn_element.auth = htod32(ssidnet[i].auth);
+ pfn_element.wpa_auth = htod32(ssidnet[i].wpa_auth);
+ pfn_element.wsec = htod32(ssidnet[i].wsec);
+
+ memcpy((char *)pfn_element.ssid.SSID, ssidnet[i].ssid.SSID, ssidnet[i].ssid.SSID_len);
+ pfn_element.ssid.SSID_len = htod32(ssidnet[i].ssid.SSID_len);
+
+ if ((len =
+ bcm_mkiovar("pfn_add", (char *)&pfn_element,
+ sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
+ if ((err =
+ dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
+ DHD_ERROR(("%s pfn_add failed with ssidnet[%d] error=%d\n",
+ __FUNCTION__, i, err));
+ return err;
+ } else {
+ DHD_TRACE(("%s pfn_add OK with ssidnet[%d]\n", __FUNCTION__, i));
+ }
+ } else {
+ DHD_ERROR(("%s bcm_mkiovar failed with ssidnet[%d]\n", __FUNCTION__, i));
+ }
+ }
+
+ return err;
+}
+
+int
dhd_pno_get_status(dhd_pub_t *dhd)
{
int ret = -1;
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
index 6ba7df1cac32..44879e4a1170 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 329682 2012-04-26 09:20:38Z $
+ * $Id: dhd_linux.c 333885 2012-05-18 00:39:03Z $
*/
#include <typedefs.h>
@@ -42,7 +42,6 @@
#include <linux/ethtool.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
-#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
@@ -1526,9 +1525,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
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) {
+ }
+#ifdef PNO_SUPPORT
+ if (event.event_type == WLC_E_PFN_NET_FOUND) {
tout_ctrl *= 2;
}
+#endif /* PNO_SUPPORT */
} else {
tout_rx = DHD_PACKET_TIMEOUT_MS;
}
@@ -2603,7 +2605,6 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
}
dhd_state |= DHD_ATTACH_STATE_NET_ALLOC;
- SET_NETDEV_DEV(net, (struct device *)dev);
/* Allocate primary dhd_info */
if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) {
DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
@@ -2941,16 +2942,20 @@ dhd_concurrent_fw(dhd_pub_t *dhd)
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));
+ DHD_ERROR(("%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;
+ return ret;
}
#endif
+/*
+ * dhd_preinit_ioctls makes special pre-setting in the firmware before radio turns on
+ * returns : 0 if all settings passed or negative value if anything failed
+*/
int
dhd_preinit_ioctls(dhd_pub_t *dhd)
{
@@ -2959,7 +2964,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
#if !defined(WL_CFG80211)
uint up = 0;
-#endif
+#endif /* defined(WL_CFG80211) */
uint power_mode = PM_FAST;
uint32 dongle_align = DHD_SDALIGN;
uint32 glom = 0;
@@ -3043,19 +3048,31 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#endif /* SET_RANDOM_MAC_SOFTAP */
DHD_TRACE(("Firmware = %s\n", fw_path));
+
#if !defined(AP) && defined(WLP2P)
/* Check if firmware with WFD support used */
+#if defined(WL_ENABLE_P2P_IF)
+ if ((ret = dhd_concurrent_fw(dhd)) < 0) {
+ DHD_ERROR(("%s error : firmware can't support p2p mode\n", __FUNCTION__));
+ goto done;
+ }
+#endif /* (WL_ENABLE_P2P_IF) */
+
if ((!op_mode && strstr(fw_path, "_p2p") != NULL)
#if defined(WL_ENABLE_P2P_IF)
- || (op_mode == 0x04) ||(dhd_concurrent_fw(dhd))
+ || (op_mode == WFD_MASK) || (dhd_concurrent_fw(dhd) == 1)
#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));
+ DHD_ERROR(("%s APSTA setting failed ret= %d\n", __FUNCTION__, ret));
} else {
dhd->op_mode |= WFD_MASK;
+#if !defined(WL_ENABLE_P2P_IF)
+ /* ICS back capability : disable any packet filtering for p2p only mode */
+ dhd_pkt_filter_enable = FALSE;
+#endif /*!defined(WL_ENABLE_P2P_IF) */
}
}
#endif
@@ -3100,16 +3117,20 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
#if defined(ARP_OFFLOAD_SUPPORT)
arpoe = 0;
#endif /* (ARP_OFFLOAD_SUPPORT) */
+ /* disable any filtering for SoftAP mode */
dhd_pkt_filter_enable = FALSE;
}
}
#endif
+#if !defined(WL_ENABLE_P2P_IF)
+ /* ICS mode setting for sta */
if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
/* STA only operation mode */
dhd->op_mode |= STA_MASK;
dhd_pkt_filter_enable = TRUE;
}
+#endif /* !defined(WL_ENABLE_P2P_IF) */
DHD_ERROR(("Firmware up: fw_path=%s op_mode=%d, "
"Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
@@ -3262,6 +3283,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd)
dhd->pktfilter[1] = NULL;
dhd->pktfilter[2] = NULL;
dhd->pktfilter[3] = NULL;
+ /* Add filter to pass multicastDNS packet and NOT filter out as Broadcast */
dhd->pktfilter[4] = "104 0 0 0 0xFFFFFFFFFFFF 0x01005E0000FB";
#if defined(SOFTAP)
if (ap_fw_loaded) {
@@ -4448,6 +4470,17 @@ dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max));
}
+/* Linux wrapper to call common dhd_pno_set_ex */
+int
+dhd_dev_pno_set_ex(struct net_device *dev, wl_pfn_t* ssidnet, int nssid,
+ ushort pno_interval, int pno_repeat, int pno_expo_max, int pno_lost_time)
+{
+ dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
+
+ return (dhd_pno_set_ex(&dhd->pub, ssidnet, nssid,
+ pno_interval, pno_repeat, pno_expo_max, pno_lost_time));
+}
+
/* Linux wrapper to get pno status */
int
dhd_dev_get_pno_status(struct net_device *dev)
@@ -4466,9 +4499,9 @@ static void dhd_hang_process(struct work_struct *work)
struct net_device *dev;
dhd = (dhd_info_t *)container_of(work, dhd_info_t, work_hang);
- dev = dhd->iflist[0]->net;
+ dev = dhd->iflist[0]->net;
- if (dev) {
+ if (dev) {
rtnl_lock();
dev_close(dev);
rtnl_unlock();
@@ -4478,7 +4511,7 @@ static void dhd_hang_process(struct work_struct *work)
#if defined(WL_CFG80211)
wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
#endif
- }
+ }
}
int net_os_send_hang_message(struct net_device *dev)
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
index 287f1c65fc9a..4d2f5763a3d9 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 295140 2011-11-09 17:22:01Z $
+ * $Id: bcmdevs.h 332966 2012-05-11 22:40:21Z $
*/
@@ -373,6 +373,7 @@
#define BFL2_EXTLNA_TX 0x08000000
#define BFL2_4313_RADIOREG 0x10000000
+#define BFL2_SECI_LOPWR_DIS 0x20000000
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
index 3bff73e2a6bc..5df25c16b7d9 100644
--- a/drivers/net/wireless/bcmdhd/include/epivers.h
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -23,6 +23,7 @@
*
*/
+
#ifndef _epivers_h_
#define _epivers_h_
@@ -32,17 +33,17 @@
#define EPI_RC_NUMBER 195
-#define EPI_INCREMENTAL_NUMBER 61
+#define EPI_INCREMENTAL_NUMBER 75
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 5, 90, 195, 61
+#define EPI_VERSION 5, 90, 195, 75
-#define EPI_VERSION_NUM 0x055ac33d
+#define EPI_VERSION_NUM 0x055ac34b
#define EPI_VERSION_DEV 5.90.195
-#define EPI_VERSION_STR "5.90.195.61"
+#define EPI_VERSION_STR "5.90.195.75"
#endif
diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h
index 69a834c6b7eb..9bfc8c9275a9 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 277737 2011-08-16 17:54:59Z $
+ * $Id: hndpmu.h 335486 2012-05-28 09:47:55Z $
*/
#ifndef _hndpmu_h_
@@ -31,4 +31,7 @@
extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on);
extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength);
+extern void si_pmu_set_otp_wr_volts(si_t *sih);
+extern void si_pmu_set_otp_rd_volts(si_t *sih);
+
#endif /* _hndpmu_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h
index 8f757509b95d..53bd2a1d5580 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 311371 2012-01-28 05:47:25Z $
+ * $Id: sbchipc.h 333924 2012-05-18 04:48:52Z $
*
* Copyright (C) 1999-2011, Broadcom Corporation
*
@@ -1441,18 +1441,18 @@ typedef volatile struct {
#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_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 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
diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h
index 6a7b93c7b977..4e7aeb71cb02 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 285387 2011-09-21 18:38:37Z $
+ * $Id: siutils.h 335486 2012-05-28 09:47:55Z $
*/
@@ -222,6 +222,8 @@ static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;}
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 void si_set_otp_wr_volts(si_t *sih);
+extern void si_set_otp_rd_volts(si_t *sih);
extern bool si_is_sprom_available(si_t *sih);
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
index 91274a0c680b..5ec0c9ade197 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 312596 2012-02-03 02:53:30Z $
+ * $Id: wlioctl.h 331292 2012-05-04 09:04:23Z $
*/
@@ -1460,6 +1460,14 @@ typedef struct wl_sampledata {
} wl_sampledata_t;
+#define WL_CHAN_VALID_HW (1 << 0)
+#define WL_CHAN_VALID_SW (1 << 1)
+#define WL_CHAN_BAND_5G (1 << 2)
+#define WL_CHAN_RADAR (1 << 3)
+#define WL_CHAN_INACTIVE (1 << 4)
+#define WL_CHAN_PASSIVE (1 << 5)
+#define WL_CHAN_RESTRICTED (1 << 6)
+
#define WL_ERROR_VAL 0x00000001
#define WL_TRACE_VAL 0x00000002
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
index f728c14622a1..2c4e9a63dd9e 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -84,17 +84,15 @@ u32 wl_dbg_level = WL_DBG_ERR;
* All the chnages in world regulatory domain are to be done here.
*/
static const struct ieee80211_regdomain brcm_regdom = {
- .n_reg_rules = 5,
+ .n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
- REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
+ REG_RULE(2412-10, 2472+10, 40, 6, 20, 0),
/* IEEE 802.11b/g, channels 12..13. No HT40
* channel fits here.
*/
- REG_RULE(2467-10, 2472+10, 20, 6, 20,
- NL80211_RRF_PASSIVE_SCAN |
- NL80211_RRF_NO_IBSS),
+ /* If any */
/*
* IEEE 802.11 channel 14 - is for JP only,
* we need cfg80211 to allow it (reg_flags = 0); so that
@@ -231,6 +229,8 @@ static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data);
static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data, bool completed);
+static s32 wl_ibss_join_done(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, bool completed);
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,
@@ -296,6 +296,7 @@ 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_inform_ibss(struct wl_priv *wl, const u8 *bssid);
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);
@@ -335,7 +336,6 @@ static void wl_link_up(struct wl_priv *wl);
static void wl_link_down(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_update_wiphybands(struct wl_priv *wl);
/*
* iscan handler
@@ -704,7 +704,7 @@ static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy)
*(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_EXTRA_BUF_MAX, false))) {
WL_ERR(("Failed to get associated bss info, use temp channel \n"));
chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
}
@@ -925,6 +925,11 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
if (wl->p2p_supported) {
memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
+
+ /* Clear GO_NEG_PHASE bit to take care of GO-NEG-FAIL cases
+ */
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared "));
+ wl_clr_p2p_status(wl, GO_NEG_PHASE);
if (wl->p2p->vif_created) {
if (wl_get_drv_status(wl, SCANNING, dev)) {
wl_notify_escan_complete(wl, dev, true, true);
@@ -1004,6 +1009,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
default:
return -EINVAL;
}
+ WL_DBG(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type));
if (ap) {
wl_set_mode_by_netdev(wl, ndev, mode);
@@ -1019,7 +1025,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
*/
chspec = wl_cfg80211_get_shared_freq(wiphy);
- wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
+ wlif_type = WL_P2P_IF_GO;
WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
ndev->name, ap, infra, type));
wl_set_p2p_status(wl, IF_CHANGING);
@@ -1043,6 +1049,14 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
return -EINVAL;
}
+ } else {
+ infra = htod32(infra);
+ err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(s32), true);
+ if (err) {
+ WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
+ return -EAGAIN;
+ }
+ wl_set_mode_by_netdev(wl, ndev, mode);
}
ndev->ieee80211_ptr->iftype = type;
@@ -1587,6 +1601,8 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
wl_cfgp2p_generate_bss_mac(&primary_mac,
&wl->p2p->dev_addr, &wl->p2p->int_addr);
}
+ wl_clr_p2p_status(wl, GO_NEG_PHASE);
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
p2p_scan(wl) = true;
}
} else {
@@ -1625,10 +1641,13 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
} else {
wpsie_len = 0;
}
- err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
- VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
- if (unlikely(err)) {
- goto scan_out;
+ if (wpsie_len > 0) {
+ err = wl_cfgp2p_set_management_ie(wl,
+ ndev, -1, VNDR_IE_PRBREQ_FLAG,
+ wpsie, wpsie_len);
+ if (unlikely(err)) {
+ goto scan_out;
+ }
}
}
}
@@ -1808,86 +1827,192 @@ wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_ibss_params *params)
{
struct wl_priv *wl = wiphy_priv(wiphy);
- struct cfg80211_bss *bss;
- struct ieee80211_channel *chan;
struct wl_join_params join_params;
- struct cfg80211_ssid ssid;
- s32 scan_retry = 0;
+ struct wlc_ssid ssid;
+ struct ether_addr bssid;
+ size_t join_params_size = 0;
+ s32 wsec = 0;
+ s32 bcnprd;
s32 err = 0;
- bool rollback_lock = false;
WL_TRACE(("In\n"));
CHECK_SYS_UP(wl);
- if (params->bssid) {
- WL_ERR(("Invalid bssid\n"));
- return -EOPNOTSUPP;
- }
- bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
- if (!bss) {
- memcpy(ssid.ssid, params->ssid, params->ssid_len);
- ssid.ssid_len = params->ssid_len;
- do {
- if (unlikely
- (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
- -EBUSY)) {
- wl_delay(150);
- } else {
- break;
- }
- } while (++scan_retry < WL_SCAN_RETRY_MAX);
- /* to allow scan_inform to propagate to cfg80211 plane */
- if (rtnl_is_locked()) {
- rtnl_unlock();
- rollback_lock = true;
- }
-
- /* wait 4 secons till scan done.... */
- schedule_timeout_interruptible(4 * HZ);
- if (rollback_lock)
- rtnl_lock();
- bss = cfg80211_get_ibss(wiphy, NULL,
- params->ssid, params->ssid_len);
- }
- if (bss) {
- wl->ibss_starter = false;
- WL_DBG(("Found IBSS\n"));
- } else {
- wl->ibss_starter = true;
- }
- chan = params->channel;
- if (chan)
- wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
+
/*
- * Join with specific BSSID and cached SSID
- * If SSID is zero join based on BSSID only
+ * Cancel ongoing scan to sync up with sme state machine of cfg80211.
*/
- memset(&join_params, 0, sizeof(join_params));
- memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
- params->ssid_len);
- join_params.ssid.SSID_len = htod32(params->ssid_len);
+ if (wl->scan_request) {
+ wl_notify_escan_complete(wl, dev, true, true);
+ }
+ /* Clean BSSID */
+ bzero(&bssid, sizeof(bssid));
+ wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID);
+
+ if (params->ssid)
+ WL_INFO(("SSID: %s\n", params->ssid));
+ else {
+ WL_ERR(("SSID: NULL, Not supported\n"));
+ err = -EOPNOTSUPP;
+ goto CleanUp;
+ }
+
if (params->bssid)
- memcpy(&join_params.params.bssid, params->bssid,
- ETHER_ADDR_LEN);
+ WL_INFO(("BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ params->bssid[0], params->bssid[1], params->bssid[2],
+ params->bssid[3], params->bssid[4], params->bssid[5]));
+
+ if (params->channel)
+ WL_INFO(("channel: %d\n", params->channel->center_freq));
+
+ if (params->channel_fixed)
+ WL_INFO(("fixed channel required\n"));
+
+ if (params->ie && params->ie_len)
+ WL_INFO(("ie len: %d\n", params->ie_len));
+
+ if (params->beacon_interval)
+ WL_INFO(("beacon interval: %d\n", params->beacon_interval));
+
+ if (params->basic_rates)
+ WL_INFO(("basic rates: %08X\n", params->basic_rates));
+
+ if (params->privacy)
+ WL_INFO(("privacy required\n"));
+
+ wl_set_drv_status(wl, CONNECTING, dev);
+
+ /* Configure Privacy for starter */
+ if (params->privacy)
+ wsec |= WEP_ENABLED;
+
+ err = wldev_iovar_setint(dev, "wsec", wsec);
+ if (err) {
+ WL_ERR(("wsec failed (%d)\n", err));
+ goto CleanUp;
+ }
+
+ err = wldev_iovar_setint(dev, "auth", WL_AUTH_OPEN_SYSTEM);
+ if (err) {
+ WL_ERR(("auth failed (%d)\n", err));
+ goto CleanUp;
+ }
+
+ err = wldev_iovar_setint(dev, "wpa_auth", 0);
+ if (err) {
+ WL_ERR(("wpa_auth failed (%d)\n", err));
+ goto CleanUp;
+ }
+
+ /* Configure Beacon Interval for starter */
+ if (params->beacon_interval)
+ bcnprd = params->beacon_interval;
else
- memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
+ bcnprd = 100;
- err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
- sizeof(join_params), false);
- if (unlikely(err)) {
- WL_ERR(("Error (%d)\n", err));
- return err;
+ bcnprd = htod32(bcnprd);
+ err = wldev_ioctl(dev, WLC_SET_BCNPRD, &bcnprd, sizeof(bcnprd), true);
+ if (err) {
+ WL_ERR(("WLC_SET_BCNPRD failed (%d)\n", err));
+ goto CleanUp;
+ }
+
+ /* Configure required join parameter */
+ memset(&join_params, 0, sizeof(struct wl_join_params));
+
+ /* SSID */
+ memset(&ssid, 0, sizeof(struct wlc_ssid));
+ ssid.SSID_len = MIN(params->ssid_len, 32);
+ join_params.ssid.SSID_len = htod32(ssid.SSID_len);
+ memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
+ memcpy(join_params.ssid.SSID, params->ssid, ssid.SSID_len);
+ join_params_size = sizeof(join_params.ssid);
+
+ wl_update_prof(wl, dev, NULL, &ssid, WL_PROF_SSID);
+
+ /* BSSID */
+ if (params->bssid) {
+ memcpy(&join_params.params.bssid, params->bssid, ETHER_ADDR_LEN);
+ join_params_size = sizeof(join_params.ssid) +
+ WL_ASSOC_PARAMS_FIXED_SIZE;
+
+ wl_update_prof(wl, dev, NULL, params->bssid, WL_PROF_BSSID);
+ } else {
+ memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
}
+
+ /* Channel */
+ if (params->channel) {
+ u32 target_channel;
+
+ target_channel = ieee80211_frequency_to_channel(
+ params->channel->center_freq);
+ if (params->channel_fixed) {
+ /* adding chanspec */
+ wl_ch_to_chanspec(target_channel,
+ &join_params, &join_params_size);
+ }
+
+ /* set channel for starter */
+ target_channel = htod32(target_channel);
+ err = wldev_ioctl(dev, WLC_SET_CHANNEL,
+ &target_channel, sizeof(target_channel), true);
+ if (err) {
+ WL_ERR(("WLC_SET_CHANNEL failed (%d)\n", err));
+ goto CleanUp;
+ }
+ }
+
+ wl->ibss_starter = false;
+
+ err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
+ if (err) {
+ WL_ERR(("WLC_SET_SSID failed (%d)\n", err));
+ goto CleanUp;
+ }
+
+CleanUp:
+
+ if (err)
+ wl_clr_drv_status(wl, CONNECTING, dev);
+
+ WL_TRACE(("Exit\n"));
return err;
}
static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
{
struct wl_priv *wl = wiphy_priv(wiphy);
+ scb_val_t scbval;
+ bool act = false;
s32 err = 0;
+ u8 *curbssid;
+
+ WL_TRACE(("Enter\n"));
CHECK_SYS_UP(wl);
- wl_link_down(wl);
+ 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_notify_escan_complete(wl, dev, true, true);
+ }
+ wl_set_drv_status(wl, DISCONNECTING, dev);
+ scbval.val = DOT11_RC_DISASSOC_LEAVING;
+ 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, dev);
+ WL_ERR(("error (%d)\n", err));
+ return err;
+ }
+ }
+ WL_TRACE(("Exit\n"));
return err;
}
@@ -2216,8 +2341,9 @@ 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_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);
}
@@ -3328,8 +3454,8 @@ wl_cfg80211_send_at_common_channel(struct wl_priv *wl,
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_ERR(("Couldn't find the peer " MACSTR " after %d retries\n",
+ MAC2STR(wl->afx_hdl->pending_tx_dst_addr.octet), wl->afx_hdl->retry));
}
wl->afx_hdl->dev = NULL;
wl->afx_hdl->bssidx = WL_INVALID;
@@ -3355,7 +3481,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
wl_af_params_t *af_params;
wifi_p2p_ie_t *p2p_ie;
wpa_ie_fixed_t *wps_ie;
+#ifdef WLWFDIE
wifi_wfd_ie_t *wfd_ie;
+#endif /* WLWFDIE */
scb_val_t scb_val;
const struct ieee80211_mgmt *mgmt;
struct wl_priv *wl = wiphy_priv(wiphy);
@@ -3364,7 +3492,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
s32 bssidx = 0;
u32 p2pie_len = 0;
u32 wpsie_len = 0;
+#ifdef WLWFDIE
u32 wfdie_len = 0;
+#endif /* WLWFDIE */
u32 id;
u32 retry = 0;
bool ack = false;
@@ -3414,11 +3544,13 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
/* Total length of P2P Information Element */
p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
}
+#ifdef WLWFDIE
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);
}
+#endif /* WLWFDIE */
if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len))
!= NULL) {
/* Order of Vendor IE is 1) WPS IE +
@@ -3430,7 +3562,11 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
sizeof(wps_ie->tag);
wl_cfgp2p_set_management_ie(wl, dev, bssidx,
VNDR_IE_PRBRSP_FLAG,
+#ifdef WLWFDIE
(u8 *)wps_ie, wpsie_len + p2pie_len + wfdie_len);
+#else
+ (u8 *)wps_ie, wpsie_len + p2pie_len);
+#endif /* WLWFDIE */
}
cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL);
goto exit;
@@ -3443,8 +3579,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
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
+ /* 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);
@@ -3513,6 +3650,36 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
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));
+ 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_REQ) {
+ WL_DBG(("P2P: GO_NEG_PHASE status set \n"));
+ wl_set_p2p_status(wl, GO_NEG_PHASE);
+ } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
+ /* If we reached till GO Neg confirmation
+ * reset the filter
+ */
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ wl_clr_p2p_status(wl, GO_NEG_PHASE);
+ }
+
+ 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;
+ }
} 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",
@@ -3523,32 +3690,13 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
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));
-
+ af_params->dwell_time = WL_MED_DWELL_TIME;
+ retry_cnt = WL_ACT_FRAME_RETRY;
}
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
*/
-
- 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)) &&
@@ -3560,6 +3708,18 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev,
/* channel offload for action request frame */
ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params);
+ /* We need to retry Service discovery frames as they don't get retried immediately by supplicant*/
+ if ((!ack) && (IS_GAS_REQ(sd_act_frm, action_frame->len))) {
+ for (retry = 1; retry < retry_cnt; retry++) {
+ WL_DBG(("Service Discovery action_frame retry %d len: %d chan %d category %d action %d\n",
+ retry, action_frame->len, af_params->channel,
+ sd_act_frm->category, sd_act_frm->action));
+ ack = (wl_cfgp2p_tx_action_frame(wl, dev,
+ af_params, bssidx)) ? false : true;
+ if (ack)
+ break;
+ }
+ }
} else {
ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
if (!ack) {
@@ -3915,13 +4075,17 @@ 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;
+#ifdef WLWFDIE
wifi_wfd_ie_t *wfd_ie;
+#endif /* WLWFDIE */
bool is_bssup = false;
bool update_bss = false;
bool pbc = false;
u16 wpsie_len = 0;
u16 p2pie_len = 0;
+#ifdef WLWFDIE
u32 wfdie_len = 0;
+#endif /* WLWFDIE */
u8 beacon_ie[IE_MAX_LEN];
s32 ie_offset = 0;
s32 bssidx = 0;
@@ -3979,24 +4143,30 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
} else {
WL_ERR(("No P2PIE in beacon \n"));
}
+#ifdef WLWFDIE
/* 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 {
+ /* 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));
+ wpsie_len, p2pie_len, wfdie_len));
wfdie_len = 0;
}
} else {
WL_ERR(("No WFDIE in beacon \n"));
}
+#endif /* WLWFDIE */
/* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
+#ifdef WLWFDIE
beacon_ie, wpsie_len + p2pie_len + wfdie_len);
+#else
+ beacon_ie, wpsie_len + p2pie_len);
+#endif /* WLWFDIE */
/* find the RSN_IE */
if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
@@ -4268,7 +4438,7 @@ exit:
#ifdef WL_SCHED_SCAN
#define PNO_TIME 30
#define PNO_REPEAT 4
-#define PNO_FREQ_EXPO_MAX 3
+#define PNO_FREQ_EXPO_MAX 2
int wl_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_sched_scan_request *request)
@@ -4523,7 +4693,7 @@ static s32 wl_inform_bss(struct wl_priv *wl)
static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
{
- struct wiphy *wiphy = wiphy_from_scan(wl);
+ struct wiphy *wiphy = wl_to_wiphy(wl);
struct ieee80211_mgmt *mgmt;
struct ieee80211_channel *channel;
struct ieee80211_supported_band *band;
@@ -4615,8 +4785,13 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
kfree(notif_bss_info);
return err;
}
+ else if( wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO) == NULL)
+ {
+ WL_DBG(("Couldn't find P2P_SEID_DEV_INFO in probe response/beacon\n"));
+ kfree(notif_bss_info);
+ return err;
+ }
}
-
if (!mgmt->u.probe_resp.timestamp) {
struct timeval tv;
@@ -4639,6 +4814,114 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
return err;
}
+static s32 wl_inform_ibss(struct wl_priv *wl, const u8 *bssid)
+{
+ struct net_device *ndev = wl_to_prmry_ndev(wl);
+ struct wiphy *wiphy = wl_to_wiphy(wl);
+ struct wl_bss_info *bi = NULL;
+ struct ieee80211_channel *notify_channel;
+ struct ieee80211_supported_band *band;
+ struct cfg80211_bss *bss;
+ s32 err = 0;
+ u16 channel;
+ u32 freq;
+ u32 wsec = 0;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ WL_TRACE(("Enter\n"));
+
+ if (wl->scan_request) {
+ wl_notify_escan_complete(wl, ndev, true, true);
+ }
+
+ mutex_lock(&wl->usr_sync);
+
+ *(u32 *)wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
+ err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, wl->extra_buf,
+ WL_EXTRA_BUF_MAX, false);
+ if (err) {
+ WL_ERR(("Failed to get bss info for IBSS\n"));
+ err = -EIO;
+ goto CleanUp;
+ }
+ bi = (struct wl_bss_info *)(wl->extra_buf + 4);
+
+ if (memcmp(bssid, &bi->BSSID, ETHER_ADDR_LEN)) {
+ WL_ERR(("BSSID mismatch: Inform %02x:%02x:%02x:%02x:%02x:%02x,"
+ "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5],
+ bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
+ bi->BSSID.octet[3], bi->BSSID.octet[4],
+ bi->BSSID.octet[5]));
+ err = -EINVAL;
+ goto CleanUp;
+ }
+
+ err = wldev_iovar_getint(ndev, "wsec", &wsec);
+ if (err) {
+ WL_ERR(("wsec failed: %d\n", err));
+ err = -EIO;
+ goto CleanUp;
+ }
+
+ channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(dtohchanspec(bi->chanspec));
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ freq = ieee80211_channel_to_frequency(channel);
+ (void)band->band;
+#else
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+#endif
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_capability = dtoh16(bi->capability);
+ notify_interval = dtoh16(bi->beacon_period);
+ notify_ie = (u8 *)bi + dtoh16(bi->ie_offset);
+ notify_ielen = dtoh32(bi->ie_length);
+ notify_signal = (int16)dtoh16(bi->RSSI) * 100;
+
+ if (wl->p2p_supported) {
+ notify_capability |= DOT11_CAP_IBSS;
+ if (wsec)
+ notify_capability |= DOT11_CAP_PRIVACY;
+ }
+
+ WL_DBG(("BSSID %02x:%02x:%02x:%02x:%02x:%02x",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]));
+ WL_INFO(("channel: %d(%d)\n", channel, freq));
+ WL_INFO(("capability: %X\n", notify_capability));
+ WL_INFO(("beacon interval: %d ms\n", notify_interval));
+ WL_INFO(("signal: %d dBm\n", notify_signal));
+ WL_INFO(("ie_len: %d\n", notify_ielen));
+ bss = cfg80211_inform_bss(wiphy, notify_channel, bssid, 0,
+ notify_capability, notify_interval,
+ notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+ if (!bss) {
+ WL_ERR(("cfg80211_inform_bss() Failed\n"));
+ err = -ENOMEM;
+ goto CleanUp;
+ }
+
+ cfg80211_put_bss(bss);
+ err = 0;
+
+CleanUp:
+
+ mutex_unlock(&wl->usr_sync);
+
+ WL_TRACE(("Exit\n"));
+ return err;
+}
+
static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev)
{
u32 event = ntoh32(e->event_type);
@@ -4648,12 +4931,12 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net
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))
- return true;
+ return true;
}
} else if (event == WLC_E_LINK) {
if (flags & WLC_EVENT_MSG_LINK)
- return true;
+ if (!wl_is_ibssmode(wl, ndev))
+ return true;
}
WL_DBG(("wl_is_linkup false\n"));
@@ -4834,7 +5117,9 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *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));
+ 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);
@@ -4843,10 +5128,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
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"));
+ wl_ibss_join_done(wl, ndev, e, data, true);
+ WL_DBG(("wl_ibss_join_done succeeded\n"));
} else {
if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) {
printk("wl_bss_connect_done succeeded\n");
@@ -4856,7 +5139,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID));
}
}
-
} else if (wl_is_linkdown(wl, e)) {
if (wl->scan_request) {
if (wl->escan_on) {
@@ -4880,15 +5162,21 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
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_ERR(("link down, calling cfg80211_disconnected"
+ " with deauth_reason:%d\n", wl->deauth_reason));
+ if (!wl_is_ibssmode(wl, ndev))
+ 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);
+ if (wl_is_ibssmode(wl, ndev))
+ wl_ibss_join_done(wl, ndev, e, data, false);
+ else
+ wl_bss_connect_done(wl, ndev, e, data, false);
}
wl_clr_drv_status(wl, DISCONNECTING, ndev);
@@ -5184,6 +5472,35 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
}
static s32
+wl_ibss_join_done(struct wl_priv *wl, struct net_device *ndev,
+ const wl_event_msg_t *e, void *data, bool completed)
+{
+ s32 err = 0;
+
+ WL_TRACE(("Enter\n"));
+
+ if (wl->scan_request) {
+ wl_notify_escan_complete(wl, ndev, true, true);
+ }
+ if (wl_get_drv_status(wl, CONNECTING, ndev)) {
+ wl_clr_drv_status(wl, CONNECTING, ndev);
+ if (completed) {
+ err = wl_inform_ibss(wl, (u8 *)&e->addr);
+ if (err) {
+ WL_ERR(("wl_inform_ibss() failed: %d\n", err));
+ }
+ wl_set_drv_status(wl, CONNECTED, ndev);
+
+ cfg80211_ibss_joined(ndev, (u8 *)&e->addr, GFP_KERNEL);
+ WL_DBG(("cfg80211_ibss_joined() called with valid BSSID\n"));
+ }
+ }
+
+ WL_TRACE(("Exit\n"));
+ return err;
+}
+
+static s32
wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
const wl_event_msg_t *e, void *data)
{
@@ -5365,6 +5682,13 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
WL_ERR(("No valid band"));
return -EINVAL;
}
+
+ if ((event == WLC_E_P2P_PROBREQ_MSG) &&
+ wl->p2p && wl_get_p2p_status(wl, GO_NEG_PHASE)) {
+ WL_DBG(("Filtering P2P probe_req while being in GO-Neg state\n"));
+ goto exit;
+ }
+
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
freq = ieee80211_channel_to_frequency(channel);
#else
@@ -5409,6 +5733,11 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
(act_frm->subtype == P2P_PAF_PROVDIS_RSP))) {
wldev_iovar_setint(dev, "mpc", 1);
}
+
+ if (act_frm && (act_frm->subtype == P2P_PAF_GON_CONF)) {
+ WL_DBG(("P2P: GO_NEG_PHASE status cleared \n"));
+ wl_clr_p2p_status(wl, GO_NEG_PHASE);
+ }
} else {
mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
}
@@ -6044,7 +6373,7 @@ static s32 wl_escan_handler(struct wl_priv *wl,
wl_scan_results_t *list;
u32 bi_length;
u32 i;
-
+ u8 *p2p_dev_addr = NULL;
WL_DBG((" enter event type : %d, status : %d \n",
ntoh32(e->event_type), ntoh32(e->status)));
/* P2P SCAN is coming from primary interface */
@@ -6086,16 +6415,18 @@ static s32 wl_escan_handler(struct wl_priv *wl,
if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) {
if (dtoh16(bi->capability) & DOT11_CAP_IBSS) {
- WL_ERR(("Ignoring IBSS result\n"));
+ WL_DBG(("Ignoring IBSS result\n"));
goto exit;
}
}
if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) {
- if (!memcmp(bi->BSSID.octet,
+ p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length);
+ if (p2p_dev_addr && !memcmp(p2p_dev_addr,
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_DBG(("ACTION FRAME SCAN : Peer " MACSTR " found, channel : %d\n",
+ MAC2STR(wl->afx_hdl->pending_tx_dst_addr.octet), channel));
wl_clr_p2p_status(wl, SCANNING);
wl->afx_hdl->peer_chan = channel;
complete(&wl->act_frm_scan);
@@ -6721,20 +7052,148 @@ eventmsg_out:
}
+static int wl_construct_reginfo(struct wl_priv *wl, s32 bw_cap)
+{
+ struct net_device *dev = wl_to_prmry_ndev(wl);
+ struct ieee80211_channel *band_chan_arr = NULL;
+ wl_uint32_list_t *list;
+ u32 i, j, index, n_2g, n_5g, band, channel, array_size;
+ u32 *n_cnt = NULL;
+ chanspec_t c = 0;
+ s32 err = BCME_OK;
+ bool update;
+ bool ht40_allowed;
+ u8 *pbuf = NULL;
+
+#define LOCAL_BUF_LEN 1024
+ pbuf = kzalloc(LOCAL_BUF_LEN, GFP_KERNEL);
+ if (pbuf == NULL) {
+ WL_ERR(("failed to allocate local buf\n"));
+ return -ENOMEM;
+ }
+
+ list = (wl_uint32_list_t *)(void *)pbuf;
+ list->count = htod32(WL_NUMCHANSPECS);
+
+ err = wldev_iovar_getbuf_bsscfg(dev, "chanspecs", NULL,
+ 0, pbuf, LOCAL_BUF_LEN, 0, &wl->ioctl_buf_sync);
+ if (err != 0) {
+ WL_ERR(("get chanspecs failed with %d\n", err));
+ kfree(pbuf);
+ return err;
+ }
+#undef LOCAL_BUF_LEN
+
+ band = array_size = n_2g = n_5g = 0;
+ for (i = 0; i < dtoh32(list->count); i++) {
+ index = 0;
+ update = FALSE;
+ ht40_allowed = FALSE;
+ c = (chanspec_t)dtoh32(list->element[i]);
+ channel = CHSPEC_CHANNEL(c);
+ if (CHSPEC_IS40(c)) {
+ if (CHSPEC_SB_UPPER(c))
+ channel += CH_10MHZ_APART;
+ else
+ channel -= CH_10MHZ_APART;
+ }
+
+ if (CHSPEC_IS2G(c) && channel <= CH_MAX_2G_CHANNEL) {
+ band_chan_arr = __wl_2ghz_channels;
+ array_size = ARRAYSIZE(__wl_2ghz_channels);
+ n_cnt = &n_2g;
+ band = IEEE80211_BAND_2GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_40ALL) ? TRUE : FALSE;
+ } else if (CHSPEC_IS5G(c) && channel > CH_MAX_2G_CHANNEL) {
+ band_chan_arr = __wl_5ghz_a_channels;
+ array_size = ARRAYSIZE(__wl_5ghz_a_channels);
+ n_cnt = &n_5g;
+ band = IEEE80211_BAND_5GHZ;
+ ht40_allowed = (bw_cap == WLC_N_BW_20ALL) ? FALSE : TRUE;
+ }
+
+ for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
+ if (band_chan_arr[j].hw_value == channel) {
+ update = TRUE;
+ break;
+ }
+ }
+
+ if (update)
+ index = j;
+ else
+ index = *n_cnt;
+
+ if (index < array_size) {
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel);
+#else
+ band_chan_arr[index].center_freq =
+ ieee80211_channel_to_frequency(channel, band);
+#endif
+ band_chan_arr[index].hw_value = channel;
+
+ if (CHSPEC_IS40(c) && ht40_allowed) {
+ u32 ht40_flag = band_chan_arr[index].flags & IEEE80211_CHAN_NO_HT40;
+ if (CHSPEC_SB_UPPER(c)) {
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
+ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40PLUS;
+ } else {
+ band_chan_arr[index].flags &= ~IEEE80211_CHAN_NO_HT40;
+ if (ht40_flag == IEEE80211_CHAN_NO_HT40)
+ band_chan_arr[index].flags |= IEEE80211_CHAN_NO_HT40MINUS;
+ }
+ } else {
+ band_chan_arr[index].flags = IEEE80211_CHAN_NO_HT40;
+ if (band == IEEE80211_BAND_2GHZ)
+ channel |= WL_CHANSPEC_BAND_2G;
+ else
+ channel |= WL_CHANSPEC_BAND_5G;
+ err = wldev_iovar_getint(dev, "per_chan_info", &channel);
+ if (!err) {
+ if (channel & WL_CHAN_RADAR) {
+ band_chan_arr[index].flags |= IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS;
+ }
+ if (channel & WL_CHAN_PASSIVE) {
+ band_chan_arr[index].flags |= IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS;
+ }
+ }
+ }
+
+ if (!update)
+ (*n_cnt)++;
+ }
+ }
+
+ __wl_band_2ghz.n_channels = n_2g;
+ __wl_band_5ghz_a.n_channels = n_5g;
+
+ kfree(pbuf);
+ return err;
+}
+
s32 wl_update_wiphybands(struct wl_priv *wl)
{
struct wiphy *wiphy;
+ struct net_device *dev;
u32 bandlist[3];
u32 nband = 0;
u32 i = 0;
s32 err = 0;
int nmode = 0;
- int bw_40 = 0;
+ int bw_cap = 0;
int index = 0;
WL_DBG(("Entry"));
+
+ if (wl == NULL)
+ wl = wlcfg_drv_priv;
+ dev = wl_to_prmry_ndev(wl);
+
memset(bandlist, 0, sizeof(bandlist));
- err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist,
+ err = wldev_ioctl(dev, WLC_GET_BANDLIST, bandlist,
sizeof(bandlist), false);
if (unlikely(err)) {
WL_ERR(("error read bandlist (%d)\n", err));
@@ -6745,41 +7204,44 @@ s32 wl_update_wiphybands(struct wl_priv *wl)
wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
- err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "nmode", &nmode);
+ err = wldev_iovar_getint(dev, "nmode", &nmode);
if (unlikely(err)) {
WL_ERR(("error reading nmode (%d)\n", err));
- }
- else {
+ } else {
/* For nmodeonly check bw cap */
- err = wldev_iovar_getint(wl_to_prmry_ndev(wl), "mimo_bw_cap", &bw_40);
+ err = wldev_iovar_getint(dev, "mimo_bw_cap", &bw_cap);
if (unlikely(err)) {
WL_ERR(("error get mimo_bw_cap (%d)\n", err));
}
}
+ err = wl_construct_reginfo(wl, bw_cap);
+ if (err) {
+ WL_ERR(("wl_construct_reginfo() fails err=%d\n", err));
+ return err;
+ }
for (i = 1; i <= nband && i < sizeof(bandlist)/sizeof(u32); i++) {
index = -1;
- if (bandlist[i] == WLC_BAND_5G) {
+ if (bandlist[i] == WLC_BAND_5G && __wl_band_5ghz_a.n_channels > 0) {
wiphy->bands[IEEE80211_BAND_5GHZ] =
&__wl_band_5ghz_a;
- index = IEEE80211_BAND_5GHZ;
- } else if (bandlist[i] == WLC_BAND_2G) {
+ index = IEEE80211_BAND_5GHZ;
+ if (bw_cap == WLC_N_BW_40ALL || bw_cap == WLC_N_BW_20IN2G_40IN5G)
+ wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ } else if (bandlist[i] == WLC_BAND_2G && __wl_band_2ghz.n_channels > 0) {
wiphy->bands[IEEE80211_BAND_2GHZ] =
&__wl_band_2ghz;
- index = IEEE80211_BAND_2GHZ;
+ index = IEEE80211_BAND_2GHZ;
+ if (bandlist[i] == WLC_BAND_2G && bw_cap == WLC_N_BW_40ALL)
+ wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
}
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.cap |=
+ IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_DSSSCCK40;
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;
}
-
- if ((index >= 0) && bw_40) {
- wiphy->bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
- }
}
wiphy_apply_custom_regulatory(wiphy, &brcm_regdom);
@@ -7106,8 +7568,7 @@ static void wl_init_eq_lock(struct wl_priv *wl)
static void wl_delay(u32 ms)
{
- if (ms < 1000 / HZ) {
- cond_resched();
+ if (in_atomic() || ms < 1000 / HZ) {
mdelay(ms);
} else {
msleep(ms);
@@ -7162,17 +7623,44 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
{
struct wl_priv *wl;
struct net_device *ndev = NULL;
+ struct ether_addr primary_mac;
s32 ret = 0;
s32 bssidx = 0;
s32 pktflag = 0;
wl = wlcfg_drv_priv;
- 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, net) ||
+
+ if (wl_get_drv_status(wl, AP_CREATING, net) ||
wl_get_drv_status(wl, AP_CREATED, net)) {
ndev = net;
bssidx = 0;
+ } else if (wl->p2p) {
+ if (net == wl->p2p_net) {
+ net = wl_to_prmry_ndev(wl);
+ }
+
+ if (!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;
+ ret = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0);
+
+ if (unlikely(ret)) {
+ goto exit;
+ }
+ }
+ if (net != wl_to_prmry_ndev(wl)) {
+ if (wl_get_mode_by_netdev(wl, net) == WL_MODE_AP) {
+ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
+ }
+ } else {
+ ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
+ bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
+ }
}
if (ndev != NULL) {
switch (type) {
@@ -7189,7 +7677,7 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
if (pktflag)
ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len);
}
-
+exit:
return ret;
}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
index fba853149c35..21446dc10708 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -136,6 +136,12 @@ do { \
#define WL_INVALID -1
+
+/* Bring down SCB Timeout to 20secs from 60secs default */
+#ifndef WL_SCB_TIMEOUT
+#define WL_SCB_TIMEOUT 20
+#endif
+
/* driver status */
enum wl_status {
WL_STATUS_READY = 0,
@@ -606,7 +612,6 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev)
#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) \
@@ -662,5 +667,6 @@ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
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_update_wiphybands(struct wl_priv *wl);
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 a34c4ad17c25..318e122004e7 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -59,6 +59,8 @@ 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 s32 wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
+ bool notify);
static const struct net_device_ops wl_cfgp2p_if_ops = {
.ndo_open = wl_cfgp2p_if_open,
@@ -338,6 +340,7 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
wl_p2p_if_t ifreq;
s32 err;
struct net_device *ndev = wl_to_prmry_ndev(wl);
+ u32 scb_timeout = WL_SCB_TIMEOUT;
ifreq.type = if_type;
ifreq.chspec = chspec;
@@ -351,6 +354,15 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync);
+
+ if (unlikely(err < 0)) {
+ printk("'wl p2p_ifadd' error %d\n", err);
+ } else if (if_type == WL_P2P_IF_GO) {
+ err = wldev_ioctl(ndev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
+ if (unlikely(err < 0))
+ printk("'wl scb_timeout' error %d\n", err);
+ }
+
return err;
}
@@ -387,6 +399,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
{
wl_p2p_if_t ifreq;
s32 err;
+ u32 scb_timeout = WL_SCB_TIMEOUT;
struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
ifreq.type = if_type;
@@ -404,6 +417,10 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
if (unlikely(err < 0)) {
printk("'wl p2p_ifupd' error %d\n", err);
+ } else if (if_type == WL_P2P_IF_GO) {
+ err = wldev_ioctl(netdev, WLC_SET_SCB_TIMEOUT, &scb_timeout, sizeof(u32), true);
+ if (unlikely(err < 0))
+ printk("'wl scb_timeout' error %d\n", err);
}
return err;
}
@@ -829,10 +846,12 @@ exit:
/* 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)
+#ifdef WLWFDIE
+ /* 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)
+#endif /* WLWFDIE */
/* Delete and Set a management vndr ie to firmware
* Parameters:
* @wl : wl_private data
@@ -957,8 +976,12 @@ 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) ||
+#ifdef WLWFDIE
wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0) ||
wl_cfgp2p_is_wfd_ie(&ie_buf[pos-2], NULL, 0))) {
+#else
+ wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
+#endif /* WLWFDIE */
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]));
@@ -984,8 +1007,12 @@ 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) ||
+#ifdef WLWFDIE
wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0) ||
wl_cfgp2p_is_wfd_ie(&ie_buf[pos-2], NULL, 0))) {
+#else
+ wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
+#endif /* WLWFDIE */
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]));
@@ -1095,18 +1122,21 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
}
return NULL;
}
+
+#ifdef WLWFDIE
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)) {
+ if (wl_cfgp2p_is_wfd_ie((uint8*)ie, &parse, &len)) {
return (wifi_wfd_ie_t *)ie;
}
}
return NULL;
}
+#endif /* WLWFDIE */
static s32
wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
@@ -1230,6 +1260,7 @@ wl_cfgp2p_listen_expired(unsigned long data)
struct wl_priv *wl = (struct wl_priv *) data;
CFGP2P_DBG((" Enter\n"));
+ memset(&msg, 0, sizeof(wl_event_msg_t));
msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
}
@@ -1237,7 +1268,7 @@ wl_cfgp2p_listen_expired(unsigned long data)
/*
* Routine for cancelling the P2P LISTEN
*/
-s32
+static s32
wl_cfgp2p_cancel_listen(struct wl_priv *wl, struct net_device *ndev,
bool notify)
{
@@ -1402,13 +1433,12 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
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->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));
+ (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
+ msecs_to_jiffies(MAX_WAIT_TIME));
if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
CFGP2P_INFO(("tx action frame operation is completed\n"));
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
index 668198d31a2e..40d9e5463fe0 100644
--- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -30,7 +30,11 @@
struct wl_priv;
extern u32 wl_dbg_level;
+
+#ifdef WLWFDIE
typedef struct wifi_p2p_ie wifi_wfd_ie_t;
+#endif /* WLWFDIE */
+
/* 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.
@@ -42,7 +46,7 @@ typedef enum {
P2PAPI_BSSCFG_MAX
} p2p_bsscfg_type_t;
-#define IE_MAX_LEN 300
+#define IE_MAX_LEN 512
/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */
struct p2p_saved_ie {
u8 p2p_probe_req_ie[IE_MAX_LEN];
@@ -91,7 +95,8 @@ enum wl_cfgp2p_status {
WLP2P_STATUS_LISTEN_EXPIRED,
WLP2P_STATUS_ACTION_TX_COMPLETED,
WLP2P_STATUS_ACTION_TX_NOACK,
- WLP2P_STATUS_SCANNING
+ WLP2P_STATUS_SCANNING,
+ WLP2P_STATUS_GO_NEG_PHASE
};
@@ -191,8 +196,10 @@ wl_cfgp2p_find_wpsie(u8 *parse, u32 len);
extern wifi_p2p_ie_t *
wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
+#ifdef WLWFDIE
extern wifi_wfd_ie_t *
wl_cfgp2p_find_wfdie(u8 *parse, u32 len);
+#endif /* WLWFDIE */
extern s32
wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
index 059929340354..6bb07650b27e 100644
--- a/drivers/net/wireless/bcmdhd/wl_iw.c
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -6341,6 +6341,7 @@ wl_iw_set_cscan(
else {
WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n",
__FUNCTION__, g_first_counter_scans));
+ res = -EBUSY;
goto exit_proc;
}
}
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index b7ceb3f858c6..35dfc506b984 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -43,4 +43,5 @@ obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_MAX8907C_CHARGER) += max8907c-charger.o
+CFLAGS_tegra_bpc_mgmt.o = -Werror
obj-$(CONFIG_TEGRA_BPC_MGMT) += tegra_bpc_mgmt.o
diff --git a/drivers/power/max17048_battery.c b/drivers/power/max17048_battery.c
index c65855f72dba..ba3d6440ab3d 100644
--- a/drivers/power/max17048_battery.c
+++ b/drivers/power/max17048_battery.c
@@ -221,10 +221,11 @@ static void max17048_work(struct work_struct *work)
if (chip->vcell != chip->lasttime_vcell ||
chip->soc != chip->lasttime_soc ||
- chip->status != chip->lasttime_status) {
+ chip->status != chip->lasttime_status) {
chip->lasttime_vcell = chip->vcell;
chip->lasttime_soc = chip->soc;
+ chip->lasttime_status = chip->status;
power_supply_changed(&chip->battery);
}
@@ -239,14 +240,13 @@ static void max17048_battery_status(enum charging_states status,
chip->ac_online = 0;
chip->usb_online = 0;
- if (chrg_type == AC)
- chip->ac_online = 1;
- else if (chrg_type == USB)
- chip->usb_online = 1;
-
- if (status == progress)
+ if (status == progress) {
chip->status = POWER_SUPPLY_STATUS_CHARGING;
- else
+ if (chrg_type == AC)
+ chip->ac_online = 1;
+ else if (chrg_type == USB)
+ chip->usb_online = 1;
+ } else
chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -592,7 +592,9 @@ static int max17048_resume(struct i2c_client *client)
return ret;
}
- schedule_delayed_work(&chip->work, MAX17048_DELAY);
+ update_charger_status();
+
+ schedule_work(&chip->work);
return 0;
}
diff --git a/drivers/power/smb349-charger.c b/drivers/power/smb349-charger.c
index 134b8154a2b9..c6dc43158b82 100644
--- a/drivers/power/smb349-charger.c
+++ b/drivers/power/smb349-charger.c
@@ -406,6 +406,19 @@ static int smb349_enable_charging(struct regulator_dev *rdev,
int ret;
if (!max_uA) {
+ /* Wait for SMB349 to debounce and get reset to POR when cable is unpluged */
+ msleep(50);
+
+ ret = smb349_read(client, SMB349_STS_REG_C);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s(): Failed in reading register"
+ "0x%02x\n", __func__, SMB349_STS_REG_C);
+ return ret;
+ }
+
+ if (ret & CHARGING)
+ return 0;
+
charger->state = stopped;
charger->chrg_type = NONE;
} else {
diff --git a/drivers/power/tps80031-charger.c b/drivers/power/tps80031-charger.c
index 93b283e0b04f..9190b7201fd6 100644
--- a/drivers/power/tps80031-charger.c
+++ b/drivers/power/tps80031-charger.c
@@ -3,7 +3,7 @@
*
* Battery charger driver for TI's tps80031
*
- * 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
@@ -65,18 +65,41 @@ struct tps80031_charger {
};
static struct tps80031_charger *charger_data;
-static uint8_t charging_current_val_code[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x27,
- 0x37, 0x28, 0x38, 0x29, 0x39, 0x2A, 0x3A, 0x2B, 0x3B, 0x2C,
- 0x3C, 0x2D, 0x3D, 0x2E,
+
+static uint8_t tps80031_get_vbus_input_current_limit_code(int max_uA)
+{
+ const uint8_t current_to_code[] = {
+ 0x0, /* 0 - 50 mA */
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, /* 50, 100, ..., 300mA */
+ 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, /* 350, 400, ..., 600mA */
+ 0xC, 0xD, 0xE, 0x27, 0x37, 0x28, /* 650, 700, ..., 900mA */
+ 0x38, 0x29, 0x39, 0x2A, 0x3A, 0x2B, /* 950, 700, ..., 1200mA */
+ 0x3B, 0x2C, 0x3C, 0x2D, 0x3D, 0x2E, /* 1200,1250, ..., 1500mA */
+ };
+ int charge_mA;
+ uint8_t code;
+
+ charge_mA = max_uA / 1000;
+ if (charge_mA < 0)
+ BUG();
+ else if (charge_mA < 1800)
+ code = current_to_code[charge_mA / 50];
+ else if (charge_mA < 2100)
+ code = 0x20; /* use 1800mA code */
+ else if (charge_mA < 2250)
+ code = 0x21; /* use 2100mA code */
+ else
+ code = 0x22; /* use 2250mA code */
+
+ return code;
};
static int set_charge_current_limit(struct regulator_dev *rdev,
int min_uA, int max_uA)
{
struct tps80031_charger *charger = rdev_get_drvdata(rdev);
- int max_vbus_current = 1500;
int max_charge_current = 1500;
+ uint8_t code;
int ret;
dev_info(charger->dev, "%s(): Min curr %dmA and max current %dmA\n",
@@ -101,13 +124,9 @@ static int set_charge_current_limit(struct regulator_dev *rdev,
return ret;
}
- max_vbus_current = min(max_uA/1000, max_vbus_current);
- max_vbus_current = max_vbus_current/50;
- if (max_vbus_current)
- max_vbus_current--;
+ code = tps80031_get_vbus_input_current_limit_code(max_uA);
ret = tps80031_update(charger->dev->parent, SLAVE_ID2,
- CHARGERUSB_CINLIMIT,
- charging_current_val_code[max_vbus_current], 0x3F);
+ CHARGERUSB_CINLIMIT, code, 0x3F);
if (ret < 0) {
dev_err(charger->dev, "%s(): Failed in writing register 0x%02x\n",
__func__, CHARGERUSB_CINLIMIT);
@@ -250,7 +269,8 @@ static int configure_charging_parameter(struct tps80031_charger *charger)
}
/* set Pre Charge current to 400mA */
- ret = tps80031_write(charger->dev->parent, SLAVE_ID2, 0xDE, 0x3);
+ ret = tps80031_write(charger->dev->parent, SLAVE_ID2,
+ CHARGERUSB_VICHRG_PC, 0x3);
if (ret < 0) {
dev_err(charger->dev, "%s(): Failed in writing register 0x%02x\n",
__func__, 0xDD);
@@ -274,27 +294,41 @@ static int configure_charging_parameter(struct tps80031_charger *charger)
return 0;
}
-static irqreturn_t linch_status_isr(int irq, void *dev_id)
+static bool tps80031_check_charging_completed(struct tps80031_charger *charger)
{
- struct tps80031_charger *charger = dev_id;
- uint8_t linch_status;
int ret;
- dev_info(charger->dev, "%s() got called\n", __func__);
+ uint8_t linch_status;
ret = tps80031_read(charger->dev->parent, SLAVE_ID2,
LINEAR_CHRG_STS, &linch_status);
if (ret < 0) {
dev_err(charger->dev, "%s(): Failed in reading register 0x%02x\n",
__func__, LINEAR_CHRG_STS);
+ return false;
+ }
+
+ if (linch_status & 0x20) {
+ charger->state = charging_state_charging_completed;
+ ret = true;
} else {
- dev_info(charger->dev, "%s():The status of LINEAR_CHRG_STS is 0x%02x\n",
- __func__, linch_status);
- if (linch_status & 0x20) {
- charger->state = charging_state_charging_completed;
- if (charger->charger_cb)
- charger->charger_cb(charger->state,
+ charger->state = charging_state_charging_in_progress;
+ ret = false;
+ }
+
+ return ret;
+}
+
+static irqreturn_t linch_status_isr(int irq, void *dev_id)
+{
+ struct tps80031_charger *charger = dev_id;
+
+ dev_info(charger->dev, "%s() got called\n", __func__);
+
+ if (tps80031_check_charging_completed(charger)) {
+ charger->state = charging_state_charging_completed;
+ if (charger->charger_cb)
+ charger->charger_cb(charger->state,
charger->charger_cb_data);
- }
}
return IRQ_HANDLED;
@@ -306,8 +340,22 @@ static irqreturn_t watchdog_expire_isr(int irq, void *dev_id)
int ret;
dev_info(charger->dev, "%s()\n", __func__);
- if (charger->state != charging_state_charging_in_progress)
- return IRQ_HANDLED;
+ if (charger->state != charging_state_charging_in_progress) {
+ /*
+ * After the charge completed, the chip can enable the
+ * charging again if battery voltage is 120mV below the
+ * charging voltage (defined by VOREG register).
+ */
+ if (tps80031_check_charging_completed(charger)) {
+ return IRQ_HANDLED;
+ } else {
+ /* "recharging" after charging completed happened */
+ charger->state = charging_state_charging_in_progress;
+ if (charger->charger_cb)
+ charger->charger_cb(charger->state,
+ charger->charger_cb_data);
+ }
+ }
/* Enable watchdog timer again*/
ret = tps80031_write(charger->dev->parent, SLAVE_ID2, CONTROLLER_WDG,
@@ -333,10 +381,18 @@ static int tps80031_charger_probe(struct platform_device *pdev)
int ret = 0;
struct device *dev = &pdev->dev;
struct tps80031_charger *charger;
- struct tps80031_charger_platform_data *pdata = pdev->dev.platform_data;
+ struct tps80031_platform_data *tps80031_pdata;
+ struct tps80031_charger_platform_data *pdata;
dev_info(dev, "%s()\n", __func__);
+ tps80031_pdata = dev_get_platdata(pdev->dev.parent);
+ if (!tps80031_pdata) {
+ dev_err(&pdev->dev, "no tps80031 platform_data specified\n");
+ return -EINVAL;
+ }
+
+ pdata = tps80031_pdata->battery_charger_pdata;
if (!pdata) {
dev_err(dev, "%s() No platform data, exiting..\n", __func__);
return -ENODEV;
diff --git a/drivers/power/tps80031_battery_gauge.c b/drivers/power/tps80031_battery_gauge.c
index 9ccfaad41441..f339b41cf039 100644
--- a/drivers/power/tps80031_battery_gauge.c
+++ b/drivers/power/tps80031_battery_gauge.c
@@ -433,6 +433,8 @@ void tps80031_battery_status(enum charging_states status, void *data)
di->usb_status = POWER_SUPPLY_STATUS_DISCHARGING;
di->ac_online = 0;
di->usb_online = 0;
+ } else if (status == charging_state_charging_completed) {
+ di->usb_status = POWER_SUPPLY_STATUS_FULL;
}
power_supply_changed(&di->usb);
power_supply_changed(&di->bat);
@@ -453,7 +455,20 @@ static int tps80031_battery_probe(struct platform_device *pdev)
uint8_t retval;
struct device *dev = &pdev->dev;
struct tps80031_device_info *di;
- struct tps80031_bg_platform_data *pdata = pdev->dev.platform_data;
+ struct tps80031_platform_data *tps80031_pdata;
+ struct tps80031_bg_platform_data *pdata;
+
+ tps80031_pdata = dev_get_platdata(pdev->dev.parent);
+ if (!tps80031_pdata) {
+ dev_err(&pdev->dev, "no tps80031 platform_data specified\n");
+ return -EINVAL;
+ }
+
+ pdata = tps80031_pdata->bg_pdata;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no battery_gauge platform data\n");
+ return -EINVAL;
+ }
di = devm_kzalloc(&pdev->dev, sizeof *di, GFP_KERNEL);
if (!di) {
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 28c58a1c19b1..88d36153ec70 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -332,12 +332,28 @@ config REGULATOR_DB8500_PRCMU
This driver supports the voltage domain regulators controlled by the
DB8500 PRCMU
+config REGULATOR_TPS51632
+ tristate "TI TPS51632 Power Regulator"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver supports TPS51632 voltage regulator chip.
+ The TPS52632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller
+ with Serial VID control and DVFS.
+
config REGULATOR_TPS6586X
tristate "TI TPS6586X Power regulators"
depends on MFD_TPS6586X
help
This driver supports TPS6586X voltage regulator chips.
+config REGULATOR_TPS65090
+ tristate "TI TPS65090 Power regulator"
+ depends on MFD_TPS65090
+ help
+ This driver provides support for the voltage regulators on the
+ TI TPS65090 PMIC.
+
config REGULATOR_TPS6524X
tristate "TI TPS6524X Power regulators"
depends on SPI
@@ -388,12 +404,6 @@ config REGULATOR_TPS6591X
help
This driver supports TPS6591X voltage regulator chips.
-config REGULATOR_TPS65090
- tristate "TI TPS65090 Power regulators"
- depends on MFD_TPS65090
- help
- This driver supports TPS65090 voltage regulator chips.
-
config REGULATOR_TPS80031
tristate "TI TPS80031 Power regulators"
depends on MFD_TPS80031
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index a25ff34afcbc..4265ea06992c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -41,6 +41,7 @@ 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_TPS51632) += tps51632-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index cbe36b93639b..26f8776f8eee 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2654,6 +2654,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
static atomic_t regulator_no = ATOMIC_INIT(0);
struct regulator_dev *rdev;
int ret, i;
+ const char *supply = NULL;
if (regulator_desc == NULL)
return ERR_PTR(-EINVAL);
@@ -2728,21 +2729,24 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (ret < 0)
goto scrub;
- if (init_data->supply_regulator) {
+ if (init_data->supply_regulator)
+ supply = init_data->supply_regulator;
+ else if (regulator_desc->supply_name)
+ supply = regulator_desc->supply_name;
+
+ if (supply) {
struct regulator_dev *r;
int found = 0;
list_for_each_entry(r, &regulator_list, list) {
- if (strcmp(rdev_get_name(r),
- init_data->supply_regulator) == 0) {
+ if (strcmp(rdev_get_name(r), supply) == 0) {
found = 1;
break;
}
}
if (!found) {
- dev_err(dev, "Failed to find supply %s\n",
- init_data->supply_regulator);
+ dev_err(dev, "Failed to find supply %s\n", supply);
ret = -ENODEV;
goto scrub;
}
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
new file mode 100644
index 000000000000..420362b5f116
--- /dev/null
+++ b/drivers/regulator/tps51632-regulator.c
@@ -0,0 +1,307 @@
+/*
+ * tps51632-regulator.c -- Maxim tps51632
+ *
+ * Regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down Driverless
+ * Controller with serial VID control and DVFS.
+ *
+ * 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/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps51632-regulator.h>
+#include <linux/slab.h>
+
+/* Register definitions */
+#define TPS51632_VOLTAGE_SELECT_REG 0x0
+#define TPS51632_VOLTAGE_BASE_REG 0x1
+#define TPS51632_OFFSET_REG 0x2
+#define TPS51632_IMON_REG 0x3
+#define TPS51632_VMAX_REG 0x4
+#define TPS51632_DVFS_CONTROL_REG 0x5
+#define TPS51632_POWER_STATE_REG 0x6
+#define TPS51632_SLEW_REGS 0x7
+#define TPS51632_FAULT_REG 0x14
+
+#define TPS51632_MAX_REG 0x15
+
+#define TPS51632_VOUT_MASK 0x7F
+#define TPS51632_VOUT_OFFSET_MASK 0x1F
+#define TPS51632_VMAX_MASK 0x7F
+#define TPS51632_VMAX_LOCK 0x80
+
+/* TPS51632_DVFS_CONTROL_REG */
+#define TPS51632_DVFS_PWMEN 0x1
+#define TPS51632_DVFS_STEP_20 0x2
+#define TPS51632_DVFS_VMAX_PG 0x4
+#define TPS51632_DVFS_PWMRST 0x8
+#define TPS51632_DVFS_OCA_EN 0x10
+#define TPS51632_DVFS_FCCM 0x20
+
+/* TPS51632_POWER_STATE_REG */
+#define TPS51632_POWER_STATE_MASK 0x03
+#define TPS51632_POWER_STATE_MULTI_PHASE_CCM 0x0
+#define TPS51632_POWER_STATE_SINGLE_PHASE_CCM 0x1
+#define TPS51632_POWER_STATE_SINGLE_PHASE_DCM 0x2
+
+#define TPS51632_MIN_VOLATGE 500000
+#define TPS51632_MAX_VOLATGE 1520000
+#define TPS51632_VOLATGE_STEP 10000
+#define TPS51632_MAX_SEL 0x7F
+
+/* TPS51632 chip information */
+struct tps51632_chip {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+
+ bool pwm_enabled;
+ unsigned int change_uv_per_us;
+};
+
+static int tps51632_dcdc_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct tps51632_chip *tps = rdev_get_drvdata(rdev);
+ unsigned int data;
+ int ret;
+ unsigned int reg = TPS51632_VOLTAGE_SELECT_REG;
+
+ if (tps->pwm_enabled)
+ reg = TPS51632_VOLTAGE_BASE_REG;
+ ret = regmap_read(tps->regmap, reg, &data);
+ if (ret < 0) {
+ dev_err(tps->dev, "reg read failed, err %d\n", ret);
+ return ret;
+ }
+ return data & TPS51632_VOUT_MASK;
+}
+
+static int tps51632_dcdc_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct tps51632_chip *tps = rdev_get_drvdata(rdev);
+ int vsel;
+ int ret;
+
+ if ((max_uV < min_uV) || (max_uV < TPS51632_MIN_VOLATGE) ||
+ (min_uV > TPS51632_MAX_VOLATGE))
+ return -EINVAL;
+
+ vsel = DIV_ROUND_UP(min_uV - TPS51632_MIN_VOLATGE,
+ TPS51632_VOLATGE_STEP) + 0x19;
+ if (selector)
+ *selector = (vsel & TPS51632_VOUT_MASK);
+
+ ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_SELECT_REG, vsel);
+ if (ret < 0)
+ dev_err(tps->dev, "reg write failed, err %d\n", ret);
+ return ret;
+}
+
+static int tps51632_dcdc_list_voltage(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ if (selector > TPS51632_MAX_SEL)
+ return -EINVAL;
+
+ return TPS51632_MIN_VOLATGE + (selector - 0x19) * TPS51632_VOLATGE_STEP;
+}
+
+static int tps51632_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,
+ unsigned int old_selector, unsigned int new_selector)
+{
+ struct tps51632_chip *tps = rdev_get_drvdata(rdev);
+ int old_uV, new_uV;
+
+ old_uV = tps51632_dcdc_list_voltage(rdev, old_selector);
+ if (old_uV < 0)
+ return old_uV;
+
+ new_uV = tps51632_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 struct regulator_ops tps51632_dcdc_ops = {
+ .get_voltage_sel = tps51632_dcdc_get_voltage_sel,
+ .set_voltage = tps51632_dcdc_set_voltage,
+ .list_voltage = tps51632_dcdc_list_voltage,
+ .set_voltage_time_sel = tps51632_dcdc_set_voltage_time_sel,
+};
+
+static int __devinit tps51632_init_dcdc(struct tps51632_chip *tps,
+ struct tps51632_regulator_platform_data *pdata)
+{
+ int ret;
+ uint8_t control = 0;
+ int vsel;
+
+ if (pdata->enable_pwm) {
+ control = TPS51632_DVFS_PWMEN;
+ tps->pwm_enabled = pdata->enable_pwm;
+ vsel = DIV_ROUND_UP(pdata->base_voltage_uV -
+ TPS51632_MIN_VOLATGE, TPS51632_VOLATGE_STEP) + 0x19;
+ ret = regmap_write(tps->regmap, TPS51632_VOLTAGE_BASE_REG,
+ vsel);
+ if (ret < 0) {
+ dev_err(tps->dev, "BASE reg write failed, err %d\n",
+ ret);
+ return ret;
+ }
+ }
+ if (pdata->dvfs_step_20mV)
+ control = TPS51632_DVFS_STEP_20;
+ if (pdata->enable_vmax_alarm)
+ control = TPS51632_DVFS_VMAX_PG;
+ if (pdata->enable_overcurrent_alram)
+ control = TPS51632_DVFS_OCA_EN;
+ if (pdata->max_voltage_uV) {
+ vsel = DIV_ROUND_UP(pdata->max_voltage_uV -
+ TPS51632_MIN_VOLATGE, TPS51632_VOLATGE_STEP) + 0x19;
+ ret = regmap_write(tps->regmap, TPS51632_VMAX_REG, vsel);
+ if (ret < 0) {
+ dev_err(tps->dev, "VMAX write failed, err %d\n", ret);
+ return ret;
+ }
+ }
+ ret = regmap_write(tps->regmap, TPS51632_DVFS_CONTROL_REG, control);
+ if (ret < 0) {
+ dev_err(tps->dev, "DVFS reg write failed, err %d\n", ret);
+ return ret;
+ }
+
+ tps->change_uv_per_us = max(6000u, pdata->slew_rate_uv_per_us);
+
+ vsel = BIT(tps->change_uv_per_us/6000 - 1);
+
+ ret = regmap_write(tps->regmap, TPS51632_SLEW_REGS, vsel);
+ if (ret < 0)
+ dev_err(tps->dev, "SLEW reg write failed, err %d\n", ret);
+ return ret;
+}
+
+static const struct regmap_config tps51632_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = TPS51632_MAX_REG - 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tps51632_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tps51632_regulator_platform_data *pdata;
+ struct regulator_dev *rdev;
+ struct tps51632_chip *tps;
+ int ret;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "No Platform data\n");
+ return -EINVAL;
+ }
+
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps) {
+ dev_err(&client->dev, "Memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ tps->dev = &client->dev;
+ tps->desc.name = id->name;
+ tps->desc.id = 0;
+ tps->desc.ops = &tps51632_dcdc_ops;
+ tps->desc.type = REGULATOR_VOLTAGE;
+ tps->desc.owner = THIS_MODULE;
+ tps->regmap = devm_regmap_init_i2c(client, &tps51632_regmap_config);
+ if (IS_ERR(tps->regmap)) {
+ ret = PTR_ERR(tps->regmap);
+ dev_err(&client->dev, "regmap init failed, err %d\n", ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, tps);
+
+ ret = tps51632_init_dcdc(tps, pdata);
+ if (ret < 0) {
+ dev_err(tps->dev, "Init failed, err = %d\n", ret);
+ return ret;
+ }
+
+ /* Register the regulators */
+ rdev = regulator_register(&tps->desc, &client->dev,
+ pdata->reg_init_data, tps);
+ if (IS_ERR(rdev)) {
+ dev_err(tps->dev, "regulator register failed\n");
+ return PTR_ERR(rdev);
+ }
+
+ tps->rdev = rdev;
+ return 0;
+}
+
+static int __devexit tps51632_remove(struct i2c_client *client)
+{
+ struct tps51632_chip *tps = i2c_get_clientdata(client);
+
+ regulator_unregister(tps->rdev);
+ return 0;
+}
+
+static const struct i2c_device_id tps51632_id[] = {
+ {.name = "tps51632",},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, tps51632_id);
+
+static struct i2c_driver tps51632_i2c_driver = {
+ .driver = {
+ .name = "tps51632",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps51632_probe,
+ .remove = __devexit_p(tps51632_remove),
+ .id_table = tps51632_id,
+};
+
+static int __init tps51632_init(void)
+{
+ return i2c_add_driver(&tps51632_i2c_driver);
+}
+subsys_initcall(tps51632_init);
+
+static void __exit tps51632_cleanup(void)
+{
+ i2c_del_driver(&tps51632_i2c_driver);
+}
+module_exit(tps51632_cleanup);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("TPS51632 voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index 7db148202436..095104f73b57 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -323,9 +323,15 @@ static int __devinit tps62360_init_dcdc(struct tps62360_chip *tps,
return ret;
}
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return false;
+}
+
static const struct regmap_config tps62360_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
+ .volatile_reg = is_volatile_reg,
.max_register = REG_CHIPID,
.cache_type = REGCACHE_RBTREE,
};
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index 8249a4b7ded2..aca2f56aa172 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -1,29 +1,25 @@
/*
- * drivers/regulator/tps65090-regulator.c
- *
* Regulator driver for tps65090 power management chip.
*
- * 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
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -32,7 +28,7 @@
#include <linux/mfd/tps65090.h>
#include <linux/regulator/tps65090-regulator.h>
-struct tps65090_regulator {
+struct tps65090_regulator_info {
int id;
/* Regulator register address.*/
u8 reg_en_reg;
@@ -40,30 +36,51 @@ struct tps65090_regulator {
/* used by regulator core */
struct regulator_desc desc;
-
- /* Device */
- struct device *dev;
};
+struct tps65090_regulator {
+ struct tps65090_regulator_info *rinfo;
+ struct device *dev;
+ struct regulator_dev *rdev;
+ bool enable_ext_control;
+ int gpio;
+ int gpio_state;
+};
static inline struct device *to_tps65090_dev(struct regulator_dev *rdev)
{
return rdev_get_dev(rdev)->parent->parent;
}
+
+static inline bool is_dcdc(int id)
+{
+ if ((id == TPS65090_REGULATOR_DCDC1) ||
+ (id == TPS65090_REGULATOR_DCDC2) ||
+ (id == TPS65090_REGULATOR_DCDC2))
+ return true;
+ return false;
+}
+
static int tps65090_reg_is_enabled(struct regulator_dev *rdev)
{
struct tps65090_regulator *ri = rdev_get_drvdata(rdev);
struct device *parent = to_tps65090_dev(rdev);
- uint8_t control;
+ uint8_t control = 0;
int ret;
- ret = tps65090_read(parent, ri->reg_en_reg, &control);
+ if (is_dcdc(ri->rinfo->desc.id) && ri->enable_ext_control) {
+ if (gpio_is_valid(ri->gpio))
+ return ri->gpio_state;
+ return 1;
+ }
+
+ ret = tps65090_read(parent, ri->rinfo->reg_en_reg, &control);
if (ret < 0) {
dev_err(&rdev->dev, "Error in reading reg 0x%x\n",
- ri->reg_en_reg);
+ ri->rinfo->reg_en_reg);
return ret;
}
- return (((control >> ri->en_bit) & 1) == 1);
+ return (((control >> ri->rinfo->en_bit) & 1) == 1);
}
static int tps65090_reg_enable(struct regulator_dev *rdev)
@@ -72,10 +89,19 @@ static int tps65090_reg_enable(struct regulator_dev *rdev)
struct device *parent = to_tps65090_dev(rdev);
int ret;
- ret = tps65090_set_bits(parent, ri->reg_en_reg, ri->en_bit);
+ if (is_dcdc(ri->rinfo->desc.id) && ri->enable_ext_control) {
+ if (gpio_is_valid(ri->gpio)) {
+ gpio_set_value(ri->gpio, 1);
+ ri->gpio_state = 1;
+ }
+ return 0;
+ }
+
+ ret = tps65090_set_bits(parent, ri->rinfo->reg_en_reg,
+ ri->rinfo->en_bit);
if (ret < 0)
dev_err(&rdev->dev, "Error in updating reg 0x%x\n",
- ri->reg_en_reg);
+ ri->rinfo->reg_en_reg);
return ret;
}
@@ -85,10 +111,19 @@ static int tps65090_reg_disable(struct regulator_dev *rdev)
struct device *parent = to_tps65090_dev(rdev);
int ret;
- ret = tps65090_clr_bits(parent, ri->reg_en_reg, ri->en_bit);
+ if (is_dcdc(ri->rinfo->desc.id) && ri->enable_ext_control) {
+ if (gpio_is_valid(ri->gpio)) {
+ gpio_set_value(ri->gpio, 0);
+ ri->gpio_state = 0;
+ }
+ return 0;
+ }
+
+ ret = tps65090_clr_bits(parent, ri->rinfo->reg_en_reg,
+ ri->rinfo->en_bit);
if (ret < 0)
dev_err(&rdev->dev, "Error in updating reg 0x%x\n",
- ri->reg_en_reg);
+ ri->rinfo->reg_en_reg);
return ret;
}
@@ -99,84 +134,209 @@ static struct regulator_ops tps65090_ops = {
.is_enabled = tps65090_reg_is_enabled,
};
-#define tps65090_REG(_id, _en_reg, _en_bit, _ops) \
+static struct regulator_ops tps65090_ldo_ops = {
+};
+
+#define tps65090_REG(_id, _sname, _en_reg, _en_bit, _ops) \
{ \
.reg_en_reg = _en_reg, \
.en_bit = _en_bit, \
- .id = TPS65090_ID_##_id, \
+ .id = TPS65090_REGULATOR_##_id, \
.desc = { \
.name = tps65090_rails(_id), \
- .id = TPS65090_ID_##_id, \
+ .supply_name = _sname, \
+ .id = TPS65090_REGULATOR_##_id, \
.ops = &_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}, \
}
-static struct tps65090_regulator TPS65090_regulator[] = {
- tps65090_REG(DCDC1, 12, 0, tps65090_ops),
- tps65090_REG(DCDC2, 13, 0, tps65090_ops),
- tps65090_REG(DCDC3, 14, 0, tps65090_ops),
- tps65090_REG(FET1, 15, 0, tps65090_ops),
- tps65090_REG(FET2, 16, 0, tps65090_ops),
- tps65090_REG(FET3, 17, 0, tps65090_ops),
- tps65090_REG(FET4, 18, 0, tps65090_ops),
- tps65090_REG(FET5, 19, 0, tps65090_ops),
- tps65090_REG(FET6, 20, 0, tps65090_ops),
- tps65090_REG(FET7, 21, 0, tps65090_ops),
+static struct tps65090_regulator_info TPS65090_regulator_info[] = {
+ tps65090_REG(DCDC1, "VSYS1", 12, 0, tps65090_ops),
+ tps65090_REG(DCDC2, "VSYS2", 13, 0, tps65090_ops),
+ tps65090_REG(DCDC3, "VSYS3", 14, 0, tps65090_ops),
+ tps65090_REG(LDO1, "VSYS_L1", 0, 0, tps65090_ldo_ops),
+ tps65090_REG(LDO2, "VSYS_L2", 0, 0, tps65090_ldo_ops),
+ tps65090_REG(FET1, "INFET1", 15, 0, tps65090_ops),
+ tps65090_REG(FET2, "INFET2", 16, 0, tps65090_ops),
+ tps65090_REG(FET3, "INFET3", 17, 0, tps65090_ops),
+ tps65090_REG(FET4, "INFET4", 18, 0, tps65090_ops),
+ tps65090_REG(FET5, "INFET5", 19, 0, tps65090_ops),
+ tps65090_REG(FET6, "INFET6", 20, 0, tps65090_ops),
+ tps65090_REG(FET7, "INFET7", 21, 0, tps65090_ops),
};
-static inline struct tps65090_regulator *find_regulator_info(int id)
+
+static inline struct tps65090_regulator_info *find_regulator_info(int id)
{
- struct tps65090_regulator *ri;
+ struct tps65090_regulator_info *rinfo;
int i;
- for (i = 0; i < ARRAY_SIZE(TPS65090_regulator); i++) {
- ri = &TPS65090_regulator[i];
- if (ri->desc.id == id)
- return ri;
+ for (i = 0; i < ARRAY_SIZE(TPS65090_regulator_info); i++) {
+ rinfo = &TPS65090_regulator_info[i];
+ if (rinfo->desc.id == id)
+ return rinfo;
}
return NULL;
}
+
+static int __devinit tps65090_regulator_preinit(int id,
+ struct tps65090_regulator *ri,
+ struct tps65090_regulator_platform_data *tps_pdata)
+{
+ int ret = 0;
+ struct device *parent = ri->dev->parent;
+
+ if (!tps_pdata->enable_ext_control) {
+ ret = tps65090_clr_bits(parent,
+ ri->rinfo->reg_en_reg, 1);
+ if (ret < 0) {
+ dev_err(ri->dev, "Error in clr reg 0x%x\n",
+ ri->rinfo->reg_en_reg);
+ return ret;
+ }
+ }
+
+ if (gpio_is_valid(tps_pdata->gpio)) {
+ int gpio_flag = GPIOF_OUT_INIT_LOW;
+ const char *sname;
+
+ sname = tps_pdata->reg_init_data->constraints.name;
+ if (!sname)
+ sname = ri->rinfo->desc.name;
+ ri->gpio_state = 0;
+ if (tps_pdata->reg_init_data->constraints.always_on ||
+ tps_pdata->reg_init_data->constraints.boot_on) {
+ gpio_flag = GPIOF_OUT_INIT_HIGH;
+ ri->gpio_state = 1;
+ }
+
+ ret = gpio_request_one(tps_pdata->gpio, gpio_flag, sname);
+ if (ret < 0) {
+ dev_err(ri->dev, "gpio request failed, e %d\n", ret);
+ return ret;
+ }
+ }
+ ret = tps65090_set_bits(parent, ri->rinfo->reg_en_reg, 1);
+ if (ret < 0) {
+ dev_err(ri->dev, "Error in setting reg 0x%x\n",
+ ri->rinfo->reg_en_reg);
+ return ret;
+ }
+ ri->enable_ext_control = true;
+ ri->gpio = tps_pdata->gpio;
+ return ret;
+}
+
static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
{
- struct tps65090_regulator *ri = NULL;
+ struct tps65090_regulator_info *rinfo = NULL;
+ struct tps65090_regulator *ri;
+ struct tps65090_regulator *pmic;
struct regulator_dev *rdev;
struct tps65090_regulator_platform_data *tps_pdata;
- int id = pdev->id;
+ struct tps65090_platform_data *tps65090_pdata;
+ int id;
+ int num;
+ int ret;
- dev_dbg(&pdev->dev, "Probing regulator %d\n", id);
+ dev_dbg(&pdev->dev, "Probing regulator\n");
- ri = find_regulator_info(id);
- if (ri == NULL) {
- dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ tps65090_pdata = dev_get_platdata(pdev->dev.parent);
+ if (!tps65090_pdata || !tps65090_pdata->num_reg_pdata) {
+ dev_err(&pdev->dev, "Proper platform data missing\n");
return -EINVAL;
}
- tps_pdata = pdev->dev.platform_data;
- ri->dev = &pdev->dev;
-
- rdev = regulator_register(&ri->desc, &pdev->dev,
- &tps_pdata->regulator, ri);
- if (IS_ERR_OR_NULL(rdev)) {
- dev_err(&pdev->dev, "failed to register regulator %s\n",
- ri->desc.name);
- return PTR_ERR(rdev);
+
+ pmic = devm_kzalloc(&pdev->dev,
+ tps65090_pdata->num_reg_pdata * sizeof(*pmic),
+ GFP_KERNEL);
+ if (!pmic) {
+ dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+ return -ENOMEM;
+ }
+
+ for (num = 0; num < tps65090_pdata->num_reg_pdata; ++num) {
+ tps_pdata = tps65090_pdata->reg_pdata[num];
+ if (!tps_pdata || !tps_pdata->reg_init_data) {
+ dev_err(&pdev->dev,
+ "Null platform data for regultor %d\n", num);
+ ret = -EINVAL;
+ goto scrub;
+ }
+
+ id = tps_pdata->id;
+ rinfo = find_regulator_info(id);
+ if (!rinfo) {
+ dev_err(&pdev->dev,
+ "invalid regulator ID %d specified\n", id);
+ ret = -EINVAL;
+ goto scrub;
+ }
+
+ ri = &pmic[num];
+ ri->dev = &pdev->dev;
+ ri->rinfo = rinfo;
+
+ if (is_dcdc(id)) {
+ ret = tps65090_regulator_preinit(id, ri, tps_pdata);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to preinit regulator %d\n", id);
+ goto scrub;
+ }
+ }
+ rdev = regulator_register(&ri->rinfo->desc, &pdev->dev,
+ tps_pdata->reg_init_data, ri);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->rinfo->desc.name);
+ ret = PTR_ERR(rdev);
+ goto scrub;
+ }
+ ri->rdev = rdev;
}
- platform_set_drvdata(pdev, rdev);
+ platform_set_drvdata(pdev, pmic);
return 0;
+
+scrub:
+ while (--num >= 0) {
+ ri = &pmic[num];
+ regulator_unregister(ri->rdev);
+ if (is_dcdc(ri->rinfo->desc.id) && (ri->enable_ext_control)) {
+ if (gpio_is_valid(ri->gpio))
+ gpio_free(ri->gpio);
+ }
+ }
+ return ret;
}
static int __devexit tps65090_regulator_remove(struct platform_device *pdev)
{
- struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct tps65090_regulator *pmic = platform_get_drvdata(pdev);
+ struct tps65090_platform_data *tps65090_pdata;
+ struct tps65090_regulator *ri;
+ int num;
+
+ tps65090_pdata = dev_get_platdata(pdev->dev.parent);
+ if (!tps65090_pdata || !tps65090_pdata->num_reg_pdata)
+ return 0;
- regulator_unregister(rdev);
+ for (num = 0; num < tps65090_pdata->num_reg_pdata; ++num) {
+ ri = &pmic[num];
+ regulator_unregister(ri->rdev);
+ if (is_dcdc(ri->rinfo->desc.id) && (ri->enable_ext_control)) {
+ if (gpio_is_valid(ri->gpio))
+ gpio_free(ri->gpio);
+ }
+ }
return 0;
}
static struct platform_driver tps65090_regulator_driver = {
.driver = {
- .name = "tps65090-regulator",
+ .name = "tps65090-pmic",
.owner = THIS_MODULE,
},
.probe = tps65090_regulator_probe,
@@ -196,5 +356,5 @@ static void __exit tps65090_regulator_exit(void)
module_exit(tps65090_regulator_exit);
MODULE_DESCRIPTION("tps65090 regulator driver");
-MODULE_ALIAS("platform:tps65090-regulator");
-MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/tps80031-regulator.c b/drivers/regulator/tps80031-regulator.c
index efc608c936ea..39b5f452692a 100644
--- a/drivers/regulator/tps80031-regulator.c
+++ b/drivers/regulator/tps80031-regulator.c
@@ -81,44 +81,48 @@
#define EXT_PWR_REQ (PWR_REQ_INPUT_PREQ1 | PWR_REQ_INPUT_PREQ2 | \
PWR_REQ_INPUT_PREQ3)
-struct tps80031_regulator {
-
+struct tps80031_regulator_info {
/* Regulator register address.*/
u8 trans_reg;
u8 state_reg;
u8 force_reg;
u8 volt_reg;
u8 volt_id;
- uint8_t trans_reg_cache;
- uint8_t state_reg_cache;
- uint8_t force_reg_cache;
- uint8_t volt_reg_cache;
-
- /* twl resource ID, for resource control state machine */
- u8 id;
/* chip constraints on regulator behavior */
u16 min_mV;
u16 max_mV;
- unsigned int tolerance_uv;
- /* regulator specific turn-on delay */
+ /* regulator specific turn-on delay as per datasheet*/
int delay;
- u8 flags;
- unsigned int platform_flags;
- unsigned int ext_ctrl_flag;
-
/* used by regulator core */
struct regulator_desc desc;
- /* Device */
- struct device *dev;
-
/*Power request bits */
int preq_bit;
};
+struct tps80031_regulator {
+ struct device *dev;
+ struct regulator_dev *rdev;
+ struct tps80031_regulator_info *rinfo;
+ unsigned int tolerance_uv;
+
+ /* Regulator specific turn-on delay if board file provided */
+ int delay;
+
+ u8 flags;
+ unsigned int platform_flags;
+ unsigned int ext_ctrl_flag;
+
+ /* Cached register */
+ uint8_t trans_reg_cache;
+ uint8_t state_reg_cache;
+ uint8_t force_reg_cache;
+ uint8_t volt_reg_cache;
+};
+
static inline struct device *to_tps80031_dev(struct regulator_dev *rdev)
{
return rdev_get_dev(rdev)->parent->parent;
@@ -178,7 +182,7 @@ static int tps80031_reg_enable(struct regulator_dev *rdev)
reg_val = (ri->state_reg_cache & ~STATE_MASK) |
(STATE_ON & STATE_MASK);
- ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val);
+ ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->state_reg, reg_val);
if (ret < 0) {
dev_err(&rdev->dev, "Error in writing the STATE register\n");
return ret;
@@ -200,7 +204,7 @@ static int tps80031_reg_disable(struct regulator_dev *rdev)
reg_val = (ri->state_reg_cache & ~STATE_MASK) |
(STATE_OFF & STATE_MASK);
- ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val);
+ ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->state_reg, reg_val);
if (ret < 0)
dev_err(&rdev->dev, "Error in writing the STATE register\n");
else
@@ -297,10 +301,11 @@ 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 >= (607700 + ri->tolerance_uv))
+ min_uV = min_uV - ri->tolerance_uv;
+
if (min_uV == 0)
vsel = 0;
else if ((min_uV >= 607700) && (min_uV <= 1300000)) {
@@ -328,6 +333,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent,
break;
case DCDC_OFFSET_EN:
+ if (min_uV >= (700000 + ri->tolerance_uv))
+ min_uV = min_uV - ri->tolerance_uv;
if (min_uV == 0)
vsel = 0;
else if ((min_uV >= 700000) && (min_uV <= 1420000)) {
@@ -355,6 +362,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent,
break;
case DCDC_EXTENDED_EN:
+ if (min_uV >= (1852000 + ri->tolerance_uv))
+ min_uV = min_uV - ri->tolerance_uv;
if (min_uV == 0)
vsel = 0;
else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
@@ -366,6 +375,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent,
break;
case DCDC_OFFSET_EN|DCDC_EXTENDED_EN:
+ if (min_uV >= (2161000 + ri->tolerance_uv))
+ min_uV = min_uV - ri->tolerance_uv;
if (min_uV == 0)
vsel = 0;
else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
@@ -381,10 +392,10 @@ static int __tps80031_dcdc_set_voltage(struct device *parent,
if (selector)
*selector = vsel;
- if (ri->force_reg) {
+ if (ri->rinfo->force_reg) {
if (((ri->force_reg_cache >> 6) & 0x3) == 0) {
- ret = tps80031_write(parent, ri->volt_id,
- ri->force_reg, vsel);
+ ret = tps80031_write(parent, ri->rinfo->volt_id,
+ ri->rinfo->force_reg, vsel);
if (ret < 0)
dev_err(ri->dev, "Error in writing the "
"force register\n");
@@ -393,7 +404,8 @@ static int __tps80031_dcdc_set_voltage(struct device *parent,
return ret;
}
}
- ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel);
+ ret = tps80031_write(parent, ri->rinfo->volt_id,
+ ri->rinfo->volt_reg, vsel);
if (ret < 0)
dev_err(ri->dev, "Error in writing the Voltage register\n");
else
@@ -416,7 +428,7 @@ static int tps80031dcdc_get_voltage(struct regulator_dev *rdev)
uint8_t vsel = 0;
int voltage = 0;
- if (ri->force_reg) {
+ if (ri->rinfo->force_reg) {
vsel = ri->force_reg_cache;
if ((vsel & SMPS_CMD_MASK) == 0)
goto decode;
@@ -507,11 +519,11 @@ static int tps80031ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
if (index == 0)
return 0;
- if ((ri->desc.id == TPS80031_ID_LDO2) &&
+ if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) &&
(ri->flags & TRACK_MODE_ENABLE))
- return (ri->min_mV + (((index - 1) * 125))/10) * 1000;
+ return (ri->rinfo->min_mV + (((index - 1) * 125))/10) * 1000;
- return (ri->min_mV + ((index - 1) * 100)) * 1000;
+ return (ri->rinfo->min_mV + ((index - 1) * 100)) * 1000;
}
static int __tps80031_ldo2_set_voltage_track_mode(struct device *parent,
@@ -545,7 +557,8 @@ static int __tps80031_ldo2_set_voltage_track_mode(struct device *parent,
}
}
- ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel);
+ ret = tps80031_write(parent, ri->rinfo->volt_id,
+ ri->rinfo->volt_reg, vsel);
if (ret < 0)
dev_err(ri->dev, "Error in writing the Voltage register\n");
else
@@ -562,10 +575,11 @@ static int __tps80031_ldo_set_voltage(struct device *parent,
int vsel;
int ret;
- if ((min_uV/1000 < ri->min_mV) || (max_uV/1000 > ri->max_mV))
+ if ((min_uV/1000 < ri->rinfo->min_mV) ||
+ (max_uV/1000 > ri->rinfo->max_mV))
return -EDOM;
- if ((ri->desc.id == TPS80031_ID_LDO2) &&
+ if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) &&
(ri->flags & TRACK_MODE_ENABLE))
return __tps80031_ldo2_set_voltage_track_mode(parent, ri,
min_uV, max_uV);
@@ -577,7 +591,8 @@ static int __tps80031_ldo_set_voltage(struct device *parent,
vsel = (min_uV/1000 - 1000)/100 + 1;
if (selector)
*selector = vsel;
- ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel);
+ ret = tps80031_write(parent, ri->rinfo->volt_id,
+ ri->rinfo->volt_reg, vsel);
if (ret < 0)
dev_err(ri->dev, "Error in writing the Voltage register\n");
else
@@ -601,10 +616,10 @@ static int tps80031ldo_get_voltage(struct regulator_dev *rdev)
uint8_t vsel;
- if ((ri->desc.id == TPS80031_ID_LDO2) &&
+ if ((ri->rinfo->desc.id == TPS80031_REGULATOR_LDO2) &&
(ri->flags & TRACK_MODE_ENABLE)) {
vsel = ri->volt_reg_cache & 0x3F;
- return (ri->min_mV + (((vsel - 1) * 125))/10) * 1000;
+ return (ri->rinfo->min_mV + (((vsel - 1) * 125))/10) * 1000;
}
vsel = ri->volt_reg_cache & LDO_VSEL_MASK;
@@ -712,6 +727,22 @@ static int tps80031vbus_get_voltage(struct regulator_dev *rdev)
return ret;
}
+static int tps80031_extreg_enable_time(struct regulator_dev *rdev)
+{
+ struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
+ return ri->delay;
+}
+
+static int tps80031_extreg_get_voltage(struct regulator_dev *rdev)
+{
+ struct tps80031_regulator *ri = rdev_get_drvdata(rdev);
+ int ret;
+ ret = tps80031_reg_is_enabled(rdev);
+ if (ret > 0)
+ return ri->rinfo->max_mV * 1000;
+ return 0;
+}
+
static struct regulator_ops tps80031dcdc_ops = {
.list_voltage = tps80031dcdc_list_voltage,
.set_voltage = tps80031dcdc_set_voltage,
@@ -740,6 +771,16 @@ static struct regulator_ops tps80031vbus_ops = {
.enable_time = tps80031_vbus_enable_time,
};
+static struct regulator_ops tps80031_ext_reg_ops = {
+ .enable = tps80031_reg_enable,
+ .disable = tps80031_reg_disable,
+ .is_enabled = tps80031_reg_is_enabled,
+ .enable_time = tps80031_extreg_enable_time,
+ .get_voltage = tps80031_extreg_get_voltage,
+};
+
+
+
#define TPS80031_REG(_id, _trans_reg, _state_reg, _force_reg, _volt_reg, \
_volt_id, min_mVolts, max_mVolts, _ops, _n_volt, _delay, \
_preq_bit) \
@@ -749,12 +790,11 @@ static struct regulator_ops tps80031vbus_ops = {
.force_reg = _force_reg, \
.volt_reg = _volt_reg, \
.volt_id = _volt_id, \
- .id = TPS80031_ID_##_id, \
.min_mV = min_mVolts, \
.max_mV = max_mVolts, \
.desc = { \
.name = tps80031_rails(_id), \
- .id = TPS80031_ID_##_id, \
+ .id = TPS80031_REGULATOR_##_id, \
.n_voltages = _n_volt, \
.ops = &_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -764,7 +804,7 @@ static struct regulator_ops tps80031vbus_ops = {
.preq_bit = _preq_bit, \
}
-static struct tps80031_regulator tps80031_regulator[] = {
+static struct tps80031_regulator_info tps80031_regulator_info[] = {
TPS80031_REG(VIO, 0x47, 0x48, 0x49, 0x4A, SLAVE_ID0, 600, 2100,
tps80031dcdc_ops, 63, 500, 4),
TPS80031_REG(SMPS1, 0x53, 0x54, 0x55, 0x56, SLAVE_ID0, 600, 2100,
@@ -798,6 +838,12 @@ static struct tps80031_regulator tps80031_regulator[] = {
tps80031ldo_ops, 25, 500, -1),
TPS80031_REG(VBUS, 0x0, 0x0, 0x00, 0x0, SLAVE_ID1, 0, 5000,
tps80031vbus_ops, 2, 200000, -1),
+ TPS80031_REG(REGEN1, 0xAE, 0xAF, 0x00, 0x0, SLAVE_ID1, 0, 3300,
+ tps80031_ext_reg_ops, 2, 500, 16),
+ TPS80031_REG(REGEN2, 0xB1, 0xB2, 0x00, 0x0, SLAVE_ID1, 0, 3300,
+ tps80031_ext_reg_ops, 2, 500, 17),
+ TPS80031_REG(SYSEN, 0xB4, 0xB5, 0x00, 0x0, SLAVE_ID1, 0, 3300,
+ tps80031_ext_reg_ops, 2, 500, 18),
};
static int tps80031_power_req_config(struct device *parent,
@@ -807,17 +853,18 @@ static int tps80031_power_req_config(struct device *parent,
int ret = 0;
uint8_t reg_val;
- if (ri->preq_bit < 0)
+ if (ri->rinfo->preq_bit < 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);
+ ri->rinfo->preq_bit, ri->rinfo->state_reg,
+ ri->rinfo->trans_reg);
if (!ret)
- ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg,
+ ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->trans_reg,
&ri->trans_reg_cache);
- if (!ret && ri->state_reg)
- ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg,
+ if (!ret && ri->rinfo->state_reg)
+ ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->state_reg,
&ri->state_reg_cache);
if (ret < 0) {
dev_err(ri->dev, "%s() fails\n", __func__);
@@ -831,11 +878,11 @@ skip_pwr_req_config:
if (tps80031_pdata->ext_ctrl_flag & PWR_ON_ON_SLEEP)
reg_val |= 0x4;
- ret = tps80031_write(parent, SLAVE_ID1, ri->trans_reg,
+ ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->trans_reg,
reg_val);
if (ret < 0)
dev_err(ri->dev, "Not able to write reg 0x%02x\n",
- ri->trans_reg);
+ ri->rinfo->trans_reg);
else
ri->trans_reg_cache = reg_val;
}
@@ -849,7 +896,7 @@ static int tps80031_regulator_preinit(struct device *parent,
int ret = 0;
uint8_t reg_val;
- if (ri->desc.id == TPS80031_ID_LDOUSB) {
+ if (ri->rinfo->desc.id == TPS80031_REGULATOR_LDOUSB) {
if (ri->platform_flags & USBLDO_INPUT_VSYS)
ret = tps80031_update(parent, SLAVE_ID1,
TPS80031_MISC2_ADD,
@@ -865,7 +912,7 @@ static int tps80031_regulator_preinit(struct device *parent,
}
}
- if (ri->desc.id == TPS80031_ID_LDO3) {
+ if (ri->rinfo->desc.id == TPS80031_REGULATOR_LDO3) {
if (ri->platform_flags & LDO3_OUTPUT_VIB)
ret = tps80031_update(parent, SLAVE_ID1,
TPS80031_MISC2_ADD,
@@ -878,31 +925,59 @@ static int tps80031_regulator_preinit(struct device *parent,
}
}
+ switch (ri->rinfo->desc.id) {
+ case TPS80031_REGULATOR_REGEN1:
+ case TPS80031_REGULATOR_REGEN2:
+ case TPS80031_REGULATOR_SYSEN:
+ if (tps80031_pdata->reg_init_data->constraints.always_on ||
+ tps80031_pdata->reg_init_data->constraints.boot_on)
+ ret = tps80031_update(parent, SLAVE_ID1,
+ ri->rinfo->state_reg, STATE_ON, STATE_MASK);
+ else
+ ret = tps80031_update(parent, SLAVE_ID1,
+ ri->rinfo->state_reg, STATE_OFF, STATE_MASK);
+ if (ret < 0) {
+ dev_err(ri->dev,
+ "state reg update failed, e %d\n", ret);
+ return ret;
+ }
+ ret = tps80031_update(parent, SLAVE_ID1,
+ ri->rinfo->trans_reg, 1, 0x3);
+ if (ret < 0) {
+ dev_err(ri->dev,
+ "trans reg update failed, e %d\n", ret);
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
if (!tps80031_pdata->init_apply)
return 0;
if (tps80031_pdata->init_uV >= 0) {
- switch (ri->desc.id) {
- case TPS80031_ID_VIO:
- case TPS80031_ID_SMPS1:
- case TPS80031_ID_SMPS2:
- case TPS80031_ID_SMPS3:
- case TPS80031_ID_SMPS4:
+ switch (ri->rinfo->desc.id) {
+ case TPS80031_REGULATOR_VIO:
+ case TPS80031_REGULATOR_SMPS1:
+ case TPS80031_REGULATOR_SMPS2:
+ case TPS80031_REGULATOR_SMPS3:
+ case TPS80031_REGULATOR_SMPS4:
ret = __tps80031_dcdc_set_voltage(parent, ri,
tps80031_pdata->init_uV,
tps80031_pdata->init_uV, 0);
break;
- case TPS80031_ID_LDO1:
- case TPS80031_ID_LDO2:
- case TPS80031_ID_LDO3:
- case TPS80031_ID_LDO4:
- case TPS80031_ID_LDO5:
- case TPS80031_ID_LDO6:
- case TPS80031_ID_LDO7:
- case TPS80031_ID_LDOUSB:
- case TPS80031_ID_LDOLN:
- case TPS80031_ID_VANA:
+ case TPS80031_REGULATOR_LDO1:
+ case TPS80031_REGULATOR_LDO2:
+ case TPS80031_REGULATOR_LDO3:
+ case TPS80031_REGULATOR_LDO4:
+ case TPS80031_REGULATOR_LDO5:
+ case TPS80031_REGULATOR_LDO6:
+ case TPS80031_REGULATOR_LDO7:
+ case TPS80031_REGULATOR_LDOUSB:
+ case TPS80031_REGULATOR_LDOLN:
+ case TPS80031_REGULATOR_VANA:
ret = __tps80031_ldo_set_voltage(parent, ri,
tps80031_pdata->init_uV,
tps80031_pdata->init_uV, 0);
@@ -915,7 +990,7 @@ static int tps80031_regulator_preinit(struct device *parent,
if (ret < 0) {
dev_err(ri->dev, "Not able to initialize voltage %d "
"for rail %d err %d\n", tps80031_pdata->init_uV,
- ri->desc.id, ret);
+ ri->rinfo->desc.id, ret);
return ret;
}
}
@@ -927,25 +1002,25 @@ static int tps80031_regulator_preinit(struct device *parent,
reg_val = (ri->state_reg_cache & ~STATE_MASK) |
(STATE_OFF & STATE_MASK);
- ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val);
+ ret = tps80031_write(parent, SLAVE_ID1, ri->rinfo->state_reg, reg_val);
if (ret < 0)
dev_err(ri->dev, "Not able to %s rail %d err %d\n",
(tps80031_pdata->init_enable) ? "enable" : "disable",
- ri->desc.id, ret);
+ ri->rinfo->desc.id, ret);
else
ri->state_reg_cache = reg_val;
return ret;
}
-static inline struct tps80031_regulator *find_regulator_info(int id)
+static inline struct tps80031_regulator_info *find_regulator_info(int id)
{
- struct tps80031_regulator *ri;
+ struct tps80031_regulator_info *rinfo;
int i;
- for (i = 0; i < ARRAY_SIZE(tps80031_regulator); i++) {
- ri = &tps80031_regulator[i];
- if (ri->desc.id == id)
- return ri;
+ for (i = 0; i < ARRAY_SIZE(tps80031_regulator_info); i++) {
+ rinfo = &tps80031_regulator_info[i];
+ if (rinfo->desc.id == id)
+ return rinfo;
}
return NULL;
}
@@ -953,30 +1028,30 @@ static void check_smps_mode_mult(struct device *parent,
struct tps80031_regulator *ri)
{
int mult_offset;
- switch (ri->desc.id) {
- case TPS80031_ID_VIO:
+ switch (ri->rinfo->desc.id) {
+ case TPS80031_REGULATOR_VIO:
mult_offset = SMPS_MULTOFFSET_VIO;
break;
- case TPS80031_ID_SMPS1:
+ case TPS80031_REGULATOR_SMPS1:
mult_offset = SMPS_MULTOFFSET_SMPS1;
break;
- case TPS80031_ID_SMPS2:
+ case TPS80031_REGULATOR_SMPS2:
mult_offset = SMPS_MULTOFFSET_SMPS2;
break;
- case TPS80031_ID_SMPS3:
+ case TPS80031_REGULATOR_SMPS3:
mult_offset = SMPS_MULTOFFSET_SMPS3;
break;
- case TPS80031_ID_SMPS4:
+ case TPS80031_REGULATOR_SMPS4:
mult_offset = SMPS_MULTOFFSET_SMPS4;
break;
- case TPS80031_ID_LDO2:
+ case TPS80031_REGULATOR_LDO2:
ri->flags = (tps80031_get_smps_mult(parent) & (1 << 5)) ?
TRACK_MODE_ENABLE : 0;
/* TRACK mode the ldo2 varies from 600mV to 1300mV */
if (ri->flags & TRACK_MODE_ENABLE) {
- ri->min_mV = 600;
- ri->max_mV = 1300;
- ri->desc.n_voltages = 57;
+ ri->rinfo->min_mV = 600;
+ ri->rinfo->max_mV = 1300;
+ ri->rinfo->desc.n_voltages = 57;
}
return;
default:
@@ -995,82 +1070,136 @@ static inline int tps80031_cache_regulator_register(struct device *parent,
{
int ret;
- ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg,
+ ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->trans_reg,
&ri->trans_reg_cache);
- if (!ret && ri->state_reg)
- ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg,
+ if (!ret && ri->rinfo->state_reg)
+ ret = tps80031_read(parent, SLAVE_ID1, ri->rinfo->state_reg,
&ri->state_reg_cache);
- if (!ret && ri->force_reg)
- ret = tps80031_read(parent, ri->volt_id, ri->force_reg,
- &ri->force_reg_cache);
- if (!ret && ri->volt_reg)
- ret = tps80031_read(parent, ri->volt_id, ri->volt_reg,
- &ri->volt_reg_cache);
+ if (!ret && ri->rinfo->force_reg)
+ ret = tps80031_read(parent, ri->rinfo->volt_id,
+ ri->rinfo->force_reg, &ri->force_reg_cache);
+ if (!ret && ri->rinfo->volt_reg)
+ ret = tps80031_read(parent, ri->rinfo->volt_id,
+ ri->rinfo->volt_reg, &ri->volt_reg_cache);
return ret;
}
static int __devinit tps80031_regulator_probe(struct platform_device *pdev)
{
- struct tps80031_regulator *ri = NULL;
- struct regulator_dev *rdev;
+ struct tps80031_platform_data *pdata = dev_get_platdata(pdev->dev.parent);
struct tps80031_regulator_platform_data *tps_pdata;
- int id = pdev->id;
- int err;
-
- dev_dbg(&pdev->dev, "Probing reulator %d\n", id);
+ struct tps80031_regulator_info *rinfo;
+ struct tps80031_regulator *ri;
+ struct tps80031_regulator *pmic;
+ struct regulator_dev *rdev;
+ int id;
+ int ret;
+ int num;
- ri = find_regulator_info(id);
- if (ri == NULL) {
- dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ if (!pdata || !pdata->num_regulator_pdata) {
+ dev_err(&pdev->dev, "Number of regulator is 0\n");
return -EINVAL;
}
- tps_pdata = pdev->dev.platform_data;
- 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;
- ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag;
-
- err = tps80031_cache_regulator_register(pdev->dev.parent, ri);
- if (err) {
- dev_err(&pdev->dev, "Register access for caching is failed\n");
- return err;
- }
- err = tps80031_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
- if (err)
- return err;
-
- err = tps80031_power_req_config(pdev->dev.parent, ri, tps_pdata);
- if (err)
- return err;
-
- rdev = regulator_register(&ri->desc, &pdev->dev,
- &tps_pdata->regulator, ri);
- if (IS_ERR_OR_NULL(rdev)) {
- dev_err(&pdev->dev, "failed to register regulator %s\n",
- ri->desc.name);
- return PTR_ERR(rdev);
+
+ pmic = devm_kzalloc(&pdev->dev,
+ pdata->num_regulator_pdata * sizeof(*pmic), GFP_KERNEL);
+ if (!pmic) {
+ dev_err(&pdev->dev, "mem alloc for pmic failed\n");
+ return -ENOMEM;
}
- platform_set_drvdata(pdev, rdev);
+ for (num = 0; num < pdata->num_regulator_pdata; ++num) {
+ tps_pdata = pdata->regulator_pdata[num];
+ if (!tps_pdata->reg_init_data) {
+ dev_err(&pdev->dev,
+ "No regulator init data for index %d\n", num);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ id = tps_pdata->regulator_id;
+ rinfo = find_regulator_info(id);
+ if (!rinfo) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ri = &pmic[num];
+ ri->rinfo = rinfo;
+ ri->dev = &pdev->dev;
+ if (tps_pdata->delay_us)
+ ri->delay = tps_pdata->delay_us;
+ else
+ ri->delay = rinfo->delay;
+ ri->tolerance_uv = tps_pdata->tolerance_uv;
+
+ check_smps_mode_mult(pdev->dev.parent, ri);
+ ri->platform_flags = tps_pdata->flags;
+ ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag;
+
+ ret = tps80031_cache_regulator_register(pdev->dev.parent, ri);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Register cache failed, err %d\n", ret);
+ goto fail;
+ }
+ ret = tps80031_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "regulator preinit failed, err %d\n", ret);
+ goto fail;
+ }
+
+ ret = tps80031_power_req_config(pdev->dev.parent, ri, tps_pdata);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "power req config failed, err %d\n", ret);
+ goto fail;
+ }
+
+ rdev = regulator_register(&ri->rinfo->desc, &pdev->dev,
+ tps_pdata->reg_init_data, ri);
+ if (IS_ERR_OR_NULL(rdev)) {
+ dev_err(&pdev->dev,
+ "register regulator failed %s\n",
+ ri->rinfo->desc.name);
+ ret = PTR_ERR(rdev);
+ goto fail;
+ }
+ ri->rdev = rdev;
+ }
+ platform_set_drvdata(pdev, pmic);
return 0;
+fail:
+ while(--num >= 0) {
+ ri = &pmic[num];
+ regulator_unregister(ri->rdev);
+ }
+ return ret;
}
static int __devexit tps80031_regulator_remove(struct platform_device *pdev)
{
- struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct tps80031_platform_data *pdata = pdev->dev.parent->platform_data;
+ struct tps80031_regulator *pmic = platform_get_drvdata(pdev);
+ struct tps80031_regulator *ri = NULL;
+ int num;
- regulator_unregister(rdev);
+ if (!pdata || !pdata->num_regulator_pdata)
+ return 0;
+
+ for (num = 0; num < pdata->num_regulator_pdata; ++num) {
+ ri = &pmic[num];
+ regulator_unregister(ri->rdev);
+ }
return 0;
}
static struct platform_driver tps80031_regulator_driver = {
.driver = {
- .name = "tps80031-regulator",
+ .name = "tps80031-regulators",
.owner = THIS_MODULE,
},
.probe = tps80031_regulator_probe,
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index be5b16284db0..249c25d2df88 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
+CFLAGS_rtc-tegra.o = -Werror
obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 28b0df836a30..12e6f3c8acfb 100644
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -33,6 +33,7 @@
#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
+ ANDROID_ALARM_PRINT_SUSPEND | \
ANDROID_ALARM_PRINT_INIT_STATUS;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
diff --git a/drivers/rtc/rtc-max77663.c b/drivers/rtc/rtc-max77663.c
index 13d8062e1def..d6dac76944d6 100644
--- a/drivers/rtc/rtc-max77663.c
+++ b/drivers/rtc/rtc-max77663.c
@@ -227,9 +227,10 @@ static inline int max77663_rtc_tm_to_reg(struct max77663_rtc *rtc, u8 *buf,
/* The wday is configured only when disabled alarm. */
if (!alarm)
buf[RTC_WEEKDAY] = (1 << tm->tm_wday);
- else
- buf[RTC_WEEKDAY] = 0;
-
+ else {
+ /* Configure its default reset value 0x01, and not enable it. */
+ buf[RTC_WEEKDAY] = 0x01;
+ }
return 0;
}
@@ -431,9 +432,9 @@ static int max77663_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_wday);
if (rtc->irq_mask & RTC_IRQ_ALARM1_MASK)
- alrm->enabled = 1;
- else
alrm->enabled = 0;
+ else
+ alrm->enabled = 1;
return 0;
}
diff --git a/drivers/rtc/rtc-tps6591x.c b/drivers/rtc/rtc-tps6591x.c
index ebc46b4cf46e..9644dc4afb42 100644
--- a/drivers/rtc/rtc-tps6591x.c
+++ b/drivers/rtc/rtc-tps6591x.c
@@ -106,6 +106,7 @@ static int tps6591x_write_regs(struct device *dev, int reg, int len,
static int tps6591x_rtc_valid_tm(struct rtc_time *tm)
{
if (tm->tm_year >= (RTC_YEAR_OFFSET + 99)
+ || tm->tm_year < (RTC_YEAR_OFFSET)
|| tm->tm_mon >= 12
|| tm->tm_mday < 1
|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + OS_REF_YEAR)
@@ -245,6 +246,12 @@ static int tps6591x_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 buff[7];
int err;
+ err = tps6591x_rtc_valid_tm(tm);
+ if (err < 0) {
+ dev_err(dev->parent, "\n Invalid Time\n");
+ return err;
+ }
+
buff[0] = tm->tm_sec;
buff[1] = tm->tm_min;
buff[2] = tm->tm_hour;
@@ -323,6 +330,12 @@ static int tps6591x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (rtc->irq == -1)
return -EIO;
+ err = tps6591x_rtc_valid_tm(&alrm->time);
+ if (err < 0) {
+ dev_err(dev->parent, "\n Invalid alarm time\n");
+ return err;
+ }
+
dev_info(dev->parent, "\n setting alarm to requested time::\n");
print_time(dev->parent, &alrm->time);
rtc_tm_to_time(&alrm->time, &seconds);
@@ -461,13 +474,20 @@ static int __devinit tps6591x_rtc_probe(struct platform_device *pdev)
return -EBUSY;
}
+ err = tps6591x_rtc_start(&pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "unable to start RTC\n");
+ return -EBUSY;
+ }
+
tps6591x_rtc_read_time(&pdev->dev, &tm);
- if ((tm.tm_year < RTC_YEAR_OFFSET || tm.tm_year > (RTC_YEAR_OFFSET + 99))){
- if (pdata->time.tm_year < 2000 || pdata->time.tm_year > 2100) {
+
+ if (tps6591x_rtc_valid_tm(&tm) < 0) {
+ if (pdata->time.tm_year < 2000 || pdata->time.tm_year >= 2100) {
memset(&pdata->time, 0, sizeof(pdata->time));
- pdata->time.tm_year = RTC_YEAR_OFFSET;
+ pdata->time.tm_year = 2000;
pdata->time.tm_mday = 1;
- } else
+ }
pdata->time.tm_year -= OS_REF_YEAR;
tps6591x_rtc_set_time(&pdev->dev, &pdata->time);
}
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
index b2b9d04171c5..44013e13fe43 100644
--- a/drivers/rtc/rtc-tps80031.c
+++ b/drivers/rtc/rtc-tps80031.c
@@ -349,12 +349,20 @@ static irqreturn_t tps80031_rtc_irq(int irq, void *data)
static int __devinit tps80031_rtc_probe(struct platform_device *pdev)
{
- struct tps80031_rtc_platform_data *pdata = pdev->dev.platform_data;
+ struct tps80031_platform_data *tps80031_pdata;
+ struct tps80031_rtc_platform_data *pdata;
struct tps80031_rtc *rtc;
struct rtc_time tm;
int err;
u8 reg;
+ tps80031_pdata = dev_get_platdata(pdev->dev.parent);
+ if (!tps80031_pdata) {
+ dev_err(&pdev->dev, "no tps80031 platform_data specified\n");
+ return -EINVAL;
+ }
+
+ pdata = tps80031_pdata->rtc_pdata;
if (!pdata) {
dev_err(&pdev->dev, "no platform_data specified\n");
return -EINVAL;
@@ -469,7 +477,7 @@ static int __devexit tps80031_rtc_remove(struct platform_device *pdev)
static struct platform_driver tps80031_rtc_driver = {
.driver = {
- .name = "rtc_tps80031",
+ .name = "tps80031-rtc",
.owner = THIS_MODULE,
},
.probe = tps80031_rtc_probe,
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 430f8200108a..831e6eabee64 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -53,7 +53,9 @@ obj-$(CONFIG_SPI_SH) += spi-sh.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o
+CFLAGS_spi-tegra.o = -Werror
obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o
+CFLAGS_spi_slave_tegra.o = -Werror
obj-$(CONFIG_SPI_SLAVE_TEGRA) += spi_slave_tegra.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
diff --git a/drivers/spi/spi-tegra.c b/drivers/spi/spi-tegra.c
index cf1b7bf40c62..5fca5e62706c 100644
--- a/drivers/spi/spi-tegra.c
+++ b/drivers/spi/spi-tegra.c
@@ -42,8 +42,6 @@
#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)
@@ -249,9 +247,6 @@ 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)
{
@@ -308,22 +303,6 @@ static int tegra_spi_clk_enable(struct spi_tegra_data *tspi)
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)
{
@@ -794,12 +773,8 @@ static void spi_tegra_start_transfer(struct spi_device *spi,
command2 = tspi->def_command2_reg;
if (is_first_of_msg) {
- 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;
- }
+ pm_runtime_get_sync(&tspi->pdev->dev);
+ tegra_spi_clk_enable(tspi);
spi_tegra_clear_status(tspi);
@@ -911,7 +886,8 @@ static int spi_tegra_setup(struct spi_device *spi)
return -EINVAL;
}
- spi_pm_runtime_get_sync(&tspi->pdev->dev);
+ pm_runtime_get_sync(&tspi->pdev->dev);
+ tegra_spi_clk_enable(tspi);
spin_lock_irqsave(&tspi->lock, flags);
val = tspi->def_command_reg;
@@ -923,7 +899,8 @@ static int spi_tegra_setup(struct spi_device *spi)
spi_tegra_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
spin_unlock_irqrestore(&tspi->lock, flags);
- spi_pm_runtime_put_sync(&tspi->pdev->dev);
+ tegra_spi_clk_disable(tspi);
+ pm_runtime_put_sync(&tspi->pdev->dev);
return 0;
}
@@ -1073,7 +1050,8 @@ static void spi_tegra_curr_transfer_complete(struct spi_tegra_data *tspi,
/* Provide delay to stablize the signal state */
spin_unlock_irqrestore(&tspi->lock, *irq_flags);
udelay(10);
- spi_pm_runtime_put_sync(&tspi->pdev->dev);
+ tegra_spi_clk_disable(tspi);
+ 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
@@ -1479,51 +1457,40 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN;
skip_dma_alloc:
- 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;
- }
- }
+ pm_runtime_enable(&pdev->dev);
/* 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 exit_pm_suspend;
- }
+ tegra_spi_clk_enable(tspi);
- /* create the workqueue for the kbc path */
+ /* create the workqueue for the spi transfer */
snprintf(spi_wq_name, sizeof(spi_wq_name), "spi_tegra-%d", pdev->id);
tspi->spi_workqueue = create_singlethread_workqueue(spi_wq_name);
if (!tspi->spi_workqueue) {
dev_err(&pdev->dev, "Failed to create work queue\n");
ret = -ENODEV;
- goto exit_master_unregister;
+ goto exit_fail_wq;
}
INIT_WORK(&tspi->spi_transfer_work, tegra_spi_transfer_work);
+ 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 exit_destry_wq;
+ }
+
return ret;
-exit_master_unregister:
- spi_unregister_master(master);
+exit_destry_wq:
+ destroy_workqueue(tspi->spi_workqueue);
+exit_fail_wq:
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);
+ tegra_spi_clk_disable(tspi);
-exit_pm_disable:
- spi_pm_runtime_disable(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
spi_tegra_deinit_dma_param(tspi, false);
@@ -1553,11 +1520,9 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
/* Disable clock if it is always enabled */
if (tspi->is_clkon_always)
- spi_pm_runtime_put_sync(&pdev->dev);
+ tegra_spi_clk_disable(tspi);
- spi_pm_runtime_disable(&pdev->dev);
- if (!spi_pm_runtime_status_suspended(&pdev->dev))
- tegra_spi_runtime_idle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
destroy_workqueue(tspi->spi_workqueue);
@@ -1612,7 +1577,7 @@ static int spi_tegra_suspend(struct device *dev)
/* Disable clock if it is always enabled */
if (tspi->is_clkon_always)
- spi_pm_runtime_put_sync(dev);
+ tegra_spi_clk_disable(tspi);
return 0;
}
@@ -1629,11 +1594,13 @@ static int spi_tegra_resume(struct device *dev)
/* Enable clock if it is always enabled */
if (tspi->is_clkon_always)
- spi_pm_runtime_get_sync(dev);
+ tegra_spi_clk_enable(tspi);
- spi_pm_runtime_get_sync(dev);
+ pm_runtime_get_sync(dev);
+ tegra_spi_clk_enable(tspi);
spi_tegra_writel(tspi, tspi->command_reg, SLINK_COMMAND);
- spi_pm_runtime_put_sync(dev);
+ tegra_spi_clk_disable(tspi);
+ pm_runtime_put_sync(dev);
spin_lock_irqsave(&tspi->lock, flags);
@@ -1656,27 +1623,7 @@ static int spi_tegra_resume(struct device *dev)
}
#endif
-static int tegra_spi_runtime_idle(struct device *dev)
-{
- struct spi_master *master = dev_get_drvdata(dev);
- struct spi_tegra_data *tspi = spi_master_get_devdata(master);
-
- return tegra_spi_clk_disable(tspi);
-}
-
-static int tegra_spi_runtime_resume(struct device *dev)
-{
- struct spi_master *master = dev_get_drvdata(dev);
- struct spi_tegra_data *tspi = spi_master_get_devdata(master);
-
- 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,
diff --git a/drivers/spi/spi_slave_tegra.c b/drivers/spi/spi_slave_tegra.c
index 7ee53730e736..e6bce127cae3 100644
--- a/drivers/spi/spi_slave_tegra.c
+++ b/drivers/spi/spi_slave_tegra.c
@@ -417,7 +417,7 @@ static unsigned int spi_tegra_read_rx_fifo_to_client_rxbuf(
u8 *rx_buf = (u8 *)t->rx_buf + tspi->cur_rx_pos;
unsigned i, count;
unsigned long x;
- unsigned int read_words;
+ unsigned int read_words = 0;
unsigned len;
fifo_status = spi_tegra_readl(tspi, SLINK_STATUS2);
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index fa76ce7678a6..3e09d57dc6d9 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -57,6 +57,8 @@ struct logger_reader {
struct logger_log *log; /* associated log */
struct list_head list; /* entry in logger_log's list */
size_t r_off; /* current read head offset */
+ bool r_all; /* reader can read all entries */
+ int r_ver; /* reader ABI version */
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
@@ -86,25 +88,71 @@ static inline struct logger_log *file_get_log(struct file *file)
}
/*
- * get_entry_len - Grabs the length of the payload of the next entry starting
- * from 'off'.
+ * get_entry_header - returns a pointer to the logger_entry header within
+ * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
+ * be provided. Typically the return value will be a pointer within
+ * 'logger->buf'. However, a pointer to 'scratch' may be returned if
+ * the log entry spans the end and beginning of the circular buffer.
+ */
+static struct logger_entry *get_entry_header(struct logger_log *log,
+ size_t off, struct logger_entry *scratch)
+{
+ size_t len = min(sizeof(struct logger_entry), log->size - off);
+ if (len != sizeof(struct logger_entry)) {
+ memcpy(((void *) scratch), log->buffer + off, len);
+ memcpy(((void *) scratch) + len, log->buffer,
+ sizeof(struct logger_entry) - len);
+ return scratch;
+ }
+
+ return (struct logger_entry *) (log->buffer + off);
+}
+
+/*
+ * get_entry_msg_len - Grabs the length of the message of the entry
+ * starting from from 'off'.
*
* Caller needs to hold log->mutex.
*/
-static __u32 get_entry_len(struct logger_log *log, size_t off)
+static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
{
- __u16 val;
+ struct logger_entry scratch;
+ struct logger_entry *entry;
- switch (log->size - off) {
- case 1:
- memcpy(&val, log->buffer + off, 1);
- memcpy(((char *) &val) + 1, log->buffer, 1);
- break;
- default:
- memcpy(&val, log->buffer + off, 2);
+ entry = get_entry_header(log, off, &scratch);
+ return entry->len;
+}
+
+static size_t get_user_hdr_len(int ver)
+{
+ if (ver < 2)
+ return sizeof(struct user_logger_entry_compat);
+ else
+ return sizeof(struct logger_entry);
+}
+
+static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
+ char __user *buf)
+{
+ void *hdr;
+ size_t hdr_len;
+ struct user_logger_entry_compat v1;
+
+ if (ver < 2) {
+ v1.len = entry->len;
+ v1.__pad = 0;
+ v1.pid = entry->pid;
+ v1.tid = entry->tid;
+ v1.sec = entry->sec;
+ v1.nsec = entry->nsec;
+ hdr = &v1;
+ hdr_len = sizeof(struct user_logger_entry_compat);
+ } else {
+ hdr = entry;
+ hdr_len = sizeof(struct logger_entry);
}
- return sizeof(struct logger_entry) + val;
+ return copy_to_user(buf, hdr, hdr_len);
}
/*
@@ -118,15 +166,30 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
char __user *buf,
size_t count)
{
+ struct logger_entry scratch;
+ struct logger_entry *entry;
size_t len;
+ size_t msg_start;
/*
- * We read from the log in two disjoint operations. First, we read from
- * the current read head offset up to 'count' bytes or to the end of
+ * First, copy the header to userspace, using the version of
+ * the header requested
+ */
+ entry = get_entry_header(log, reader->r_off, &scratch);
+ if (copy_header_to_user(reader->r_ver, entry, buf))
+ return -EFAULT;
+
+ count -= get_user_hdr_len(reader->r_ver);
+ buf += get_user_hdr_len(reader->r_ver);
+ msg_start = logger_offset(reader->r_off + sizeof(struct logger_entry));
+
+ /*
+ * We read from the msg in two disjoint operations. First, we read from
+ * the current msg head offset up to 'count' bytes or to the end of
* the log, whichever comes first.
*/
- len = min(count, log->size - reader->r_off);
- if (copy_to_user(buf, log->buffer + reader->r_off, len))
+ len = min(count, log->size - msg_start);
+ if (copy_to_user(buf, log->buffer + msg_start, len))
return -EFAULT;
/*
@@ -137,9 +200,34 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
if (copy_to_user(buf + len, log->buffer, count - len))
return -EFAULT;
- reader->r_off = logger_offset(reader->r_off + count);
+ reader->r_off = logger_offset(reader->r_off +
+ sizeof(struct logger_entry) + count);
- return count;
+ return count + get_user_hdr_len(reader->r_ver);
+}
+
+/*
+ * get_next_entry_by_uid - Starting at 'off', returns an offset into
+ * 'log->buffer' which contains the first entry readable by 'euid'
+ */
+static size_t get_next_entry_by_uid(struct logger_log *log,
+ size_t off, uid_t euid)
+{
+ while (off != log->w_off) {
+ struct logger_entry *entry;
+ struct logger_entry scratch;
+ size_t next_len;
+
+ entry = get_entry_header(log, off, &scratch);
+
+ if (entry->euid == euid)
+ return off;
+
+ next_len = sizeof(struct logger_entry) + entry->len;
+ off = logger_offset(off + next_len);
+ }
+
+ return off;
}
/*
@@ -151,7 +239,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
* - If there are no log entries to read, blocks until log is written to
* - Atomically reads exactly one log entry
*
- * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read
+ * Will set errno to EINVAL if read
* buffer is insufficient to hold next entry.
*/
static ssize_t logger_read(struct file *file, char __user *buf,
@@ -191,6 +279,10 @@ start:
mutex_lock(&log->mutex);
+ if (!reader->r_all)
+ reader->r_off = get_next_entry_by_uid(log,
+ reader->r_off, current_euid());
+
/* is there still something to read or did we race? */
if (unlikely(log->w_off == reader->r_off)) {
mutex_unlock(&log->mutex);
@@ -198,7 +290,8 @@ start:
}
/* get the size of the next entry */
- ret = get_entry_len(log, reader->r_off);
+ ret = get_user_hdr_len(reader->r_ver) +
+ get_entry_msg_len(log, reader->r_off);
if (count < ret) {
ret = -EINVAL;
goto out;
@@ -224,7 +317,8 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
size_t count = 0;
do {
- size_t nr = get_entry_len(log, off);
+ size_t nr = sizeof(struct logger_entry) +
+ get_entry_msg_len(log, off);
off = logger_offset(off + nr);
count += nr;
} while (count < len);
@@ -336,7 +430,9 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
header.tid = current->pid;
header.sec = now.tv_sec;
header.nsec = now.tv_nsec;
+ header.euid = current_euid();
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
+ header.hdr_size = sizeof(struct logger_entry);
/* null writes succeed, return zero */
if (unlikely(!header.len))
@@ -409,6 +505,10 @@ static int logger_open(struct inode *inode, struct file *file)
return -ENOMEM;
reader->log = log;
+ reader->r_ver = 1;
+ reader->r_all = in_egroup_p(inode->i_gid) ||
+ capable(CAP_SYSLOG);
+
INIT_LIST_HEAD(&reader->list);
mutex_lock(&log->mutex);
@@ -463,6 +563,10 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
poll_wait(file, &log->wq, wait);
mutex_lock(&log->mutex);
+ if (!reader->r_all)
+ reader->r_off = get_next_entry_by_uid(log,
+ reader->r_off, current_euid());
+
if (log->w_off != reader->r_off)
ret |= POLLIN | POLLRDNORM;
mutex_unlock(&log->mutex);
@@ -470,11 +574,25 @@ static unsigned int logger_poll(struct file *file, poll_table *wait)
return ret;
}
+static long logger_set_version(struct logger_reader *reader, void __user *arg)
+{
+ int version;
+ if (copy_from_user(&version, arg, sizeof(int)))
+ return -EFAULT;
+
+ if ((version < 1) || (version > 2))
+ return -EINVAL;
+
+ reader->r_ver = version;
+ return 0;
+}
+
static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct logger_log *log = file_get_log(file);
struct logger_reader *reader;
- long ret = -ENOTTY;
+ long ret = -EINVAL;
+ void __user *argp = (void __user *) arg;
mutex_lock(&log->mutex);
@@ -499,8 +617,14 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
reader = file->private_data;
+
+ if (!reader->r_all)
+ reader->r_off = get_next_entry_by_uid(log,
+ reader->r_off, current_euid());
+
if (log->w_off != reader->r_off)
- ret = get_entry_len(log, reader->r_off);
+ ret = get_user_hdr_len(reader->r_ver) +
+ get_entry_msg_len(log, reader->r_off);
else
ret = 0;
break;
@@ -514,6 +638,22 @@ static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
log->head = log->w_off;
ret = 0;
break;
+ case LOGGER_GET_VERSION:
+ if (!(file->f_mode & FMODE_READ)) {
+ ret = -EBADF;
+ break;
+ }
+ reader = file->private_data;
+ ret = reader->r_ver;
+ break;
+ case LOGGER_SET_VERSION:
+ if (!(file->f_mode & FMODE_READ)) {
+ ret = -EBADF;
+ break;
+ }
+ reader = file->private_data;
+ ret = logger_set_version(reader, argp);
+ break;
}
mutex_unlock(&log->mutex);
@@ -534,8 +674,8 @@ static const struct file_operations logger_fops = {
/*
* Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
- * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
- * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
+ * must be a power of two, and greater than
+ * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
*/
#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
static unsigned char _buf_ ## VAR[SIZE]; \
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
index 2cb06e9d8f98..3f612a3b101c 100644
--- a/drivers/staging/android/logger.h
+++ b/drivers/staging/android/logger.h
@@ -20,7 +20,12 @@
#include <linux/types.h>
#include <linux/ioctl.h>
-struct logger_entry {
+/*
+ * The userspace structure for version 1 of the logger_entry ABI.
+ * This structure is returned to userspace unless the caller requests
+ * an upgrade to a newer ABI version.
+ */
+struct user_logger_entry_compat {
__u16 len; /* length of the payload */
__u16 __pad; /* no matter what, we get 2 bytes of padding */
__s32 pid; /* generating process's pid */
@@ -30,14 +35,28 @@ struct logger_entry {
char msg[0]; /* the entry's payload */
};
+/*
+ * The structure for version 2 of the logger_entry ABI.
+ * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
+ * is called with version >= 2
+ */
+struct logger_entry {
+ __u16 len; /* length of the payload */
+ __u16 hdr_size; /* sizeof(struct logger_entry_v2) */
+ __s32 pid; /* generating process's pid */
+ __s32 tid; /* generating process's tid */
+ __s32 sec; /* seconds since Epoch */
+ __s32 nsec; /* nanoseconds */
+ uid_t euid; /* effective UID of logger */
+ char msg[0]; /* the entry's payload */
+};
+
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */
#define LOGGER_LOG_MAIN "log_main" /* everything else */
-#define LOGGER_ENTRY_MAX_LEN (4*1024)
-#define LOGGER_ENTRY_MAX_PAYLOAD \
- (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
+#define LOGGER_ENTRY_MAX_PAYLOAD 4076
#define __LOGGERIO 0xAE
@@ -45,5 +64,7 @@ struct logger_entry {
#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
+#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
+#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
#endif /* _LINUX_LOGGER_H */
diff --git a/drivers/staging/brcm80211/Kconfig b/drivers/staging/brcm80211/Kconfig
index 379cf16e89f7..586de7f74f5f 100644
--- a/drivers/staging/brcm80211/Kconfig
+++ b/drivers/staging/brcm80211/Kconfig
@@ -21,7 +21,6 @@ config BRCMFMAC
default n
depends on MMC
depends on WLAN && CFG80211
- depends on X86 || MIPS
select BRCMUTIL
select FW_LOADER
select WIRELESS_EXT
diff --git a/drivers/staging/brcm80211/Makefile b/drivers/staging/brcm80211/Makefile
index 8b01f5e7ba25..b595cab91e0b 100644
--- a/drivers/staging/brcm80211/Makefile
+++ b/drivers/staging/brcm80211/Makefile
@@ -16,8 +16,8 @@
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# common flags
-subdir-ccflags-y := -DBCMDMA32
-subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG
+subdir-ccflags-y := -DBCMDMA32
+subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG -DBCMDBG_ASSERT
obj-$(CONFIG_BRCMUTIL) += brcmutil/
obj-$(CONFIG_BRCMFMAC) += brcmfmac/
diff --git a/drivers/staging/brcm80211/README b/drivers/staging/brcm80211/README
index bb86b1b3e58e..8ad558675bd3 100644
--- a/drivers/staging/brcm80211/README
+++ b/drivers/staging/brcm80211/README
@@ -1 +1,64 @@
-refer to: http://linuxwireless.org/en/users/Drivers/brcm80211
+Broadcom brcmsmac (mac80211-based softmac PCIe) and brcmfmac (SDIO) drivers.
+
+Completely open source host drivers, no binary object files.
+
+Support for the following chips:
+===============================
+
+ brcmsmac (PCIe)
+ Name Device ID
+ BCM4313 0x4727
+ BCM43224 0x4353
+ BCM43225 0x4357
+
+ brcmfmac (SDIO)
+ Name
+ BCM4329
+
+Both brcmsmac and brcmfmac drivers require firmware files that need to be
+separately downloaded.
+
+Firmware
+======================
+Firmware is available from the Linux firmware repository at:
+
+ git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git
+ http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
+ https://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
+
+
+===============================================================
+Broadcom brcmsmac driver
+===============================================================
+- Support for both 32 and 64 bit Linux kernels
+
+
+Firmware installation
+======================
+Copy brcm/bcm43xx-0.fw and brcm/bcm43xx_hdr-0.fw to
+/lib/firmware/brcm (or wherever firmware is normally installed
+on your system).
+
+
+===============================================================
+Broadcom brcmfmac driver
+===============================================================
+- Support for 32 bit Linux kernel, 64 bit untested
+
+
+Firmware installation
+======================
+Copy brcm/bcm4329-fullmac-4.bin and brcm/bcm4329-fullmac-4.txt
+to /lib/firmware/brcm (or wherever firmware is normally installed on your
+system).
+
+
+Contact Info:
+=============
+Brett Rudley brudley@broadcom.com
+Henry Ptasinski henryp@broadcom.com
+Dowan Kim dowan@broadcom.com
+Roland Vossen rvossen@broadcom.com
+Arend van Spriel arend@broadcom.com
+
+For more info, refer to: http://linuxwireless.org/en/users/Drivers/brcm80211
diff --git a/drivers/staging/brcm80211/TODO b/drivers/staging/brcm80211/TODO
deleted file mode 100644
index e2e2ef9bd7ac..000000000000
--- a/drivers/staging/brcm80211/TODO
+++ /dev/null
@@ -1,13 +0,0 @@
-To Do List for Broadcom Mac80211 driver before getting in mainline
-
-Bugs
-====
-- none known at this moment
-
-brcmfmac
-=====================
-- ASSERTS deprecated in mainline, replace by warning + error handling
-
-brcm80211 info page
-=====================
-http://linuxwireless.org/en/users/Drivers/brcm80211
diff --git a/drivers/staging/brcm80211/brcmfmac/Makefile b/drivers/staging/brcm80211/brcmfmac/Makefile
index da3c80575907..71c7fe94ece8 100644
--- a/drivers/staging/brcm80211/brcmfmac/Makefile
+++ b/drivers/staging/brcm80211/brcmfmac/Makefile
@@ -15,17 +15,12 @@
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-ccflags-y := \
- -DBRCMF_FIRSTREAD=64 \
- -DBRCMF_SDALIGN=64 \
- -DMAX_HDR_READ=64
-
-ccflags-$(CONFIG_BRCMDBG) += -DSHOW_EVENTS
-
ccflags-y += \
-Idrivers/staging/brcm80211/brcmfmac \
-Idrivers/staging/brcm80211/include
+ccflags-y += -DISR_THREAD
+
DHDOFILES = \
wl_cfg80211.o \
dhd_cdc.o \
@@ -37,3 +32,4 @@ DHDOFILES = \
obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += $(DHDOFILES)
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c
index f4e72ed126b0..bff9dcd6fadc 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh.c
@@ -21,6 +21,9 @@
#include <linux/pci_ids.h>
#include <linux/sched.h>
#include <linux/completion.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
#include <defs.h>
#include <brcm_hw_ids.h>
@@ -29,304 +32,103 @@
#include <soc.h>
#include "dhd.h"
#include "dhd_bus.h"
+#include "dhd_dbg.h"
#include "sdio_host.h"
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
-#define BRCMF_SD_ERROR_VAL 0x0001 /* Error */
-#define BRCMF_SD_INFO_VAL 0x0002 /* Info */
-
-
-#ifdef BCMDBG
-#define BRCMF_SD_ERROR(x) \
- do { \
- if ((brcmf_sdio_msglevel & BRCMF_SD_ERROR_VAL) && \
- net_ratelimit()) \
- printk x; \
- } while (0)
-#define BRCMF_SD_INFO(x) \
- do { \
- if ((brcmf_sdio_msglevel & BRCMF_SD_INFO_VAL) && \
- net_ratelimit()) \
- printk x; \
- } while (0)
-#else /* BCMDBG */
-#define BRCMF_SD_ERROR(x)
-#define BRCMF_SD_INFO(x)
-#endif /* BCMDBG */
-
-/* debugging macros */
-#define SDLX_MSG(x)
-
-#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */
-#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */
-#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */
-
-#define SDIOH_DATA_PIO 0 /* PIO mode */
-#define SDIOH_DATA_DMA 1 /* DMA mode */
-
-struct brcmf_sdio_card {
- bool init_success; /* underlying driver successfully attached */
- void *sdioh; /* handler for sdioh */
- u32 vendevid; /* Target Vendor and Device ID on SD bus */
- bool regfail; /* Save status of last
- reg_read/reg_write call */
- u32 sbwad; /* Save backplane window address */
-};
-
-/**
- * SDIO Host Controller info
- */
-struct sdio_hc {
- struct sdio_hc *next;
- struct device *dev; /* platform device handle */
- void *regs; /* SDIO Host Controller address */
- struct brcmf_sdio_card *card;
- void *ch;
- unsigned int oob_irq;
- unsigned long oob_flags; /* OOB Host specifiction
- as edge and etc */
- bool oob_irq_registered;
-};
-
-/* local copy of bcm sd handler */
-static struct brcmf_sdio_card *l_card;
-
-const uint brcmf_sdio_msglevel = BRCMF_SD_ERROR_VAL;
-
-static struct sdio_hc *sdhcinfo;
-
-/* driver info, initialized when brcmf_sdio_register is called */
-static struct brcmf_sdioh_driver drvinfo = { NULL, NULL };
-
-/* Module parameters specific to each host-controller driver */
-
-module_param(sd_msglevel, uint, 0);
-
-extern uint sd_f2_blocksize;
-module_param(sd_f2_blocksize, int, 0);
-
-/* forward declarations */
-int brcmf_sdio_probe(struct device *dev);
-EXPORT_SYMBOL(brcmf_sdio_probe);
-
-int brcmf_sdio_remove(struct device *dev);
-EXPORT_SYMBOL(brcmf_sdio_remove);
-
-struct brcmf_sdio_card*
-brcmf_sdcard_attach(void *cfghdl, u32 *regsva, uint irq)
+static void brcmf_sdioh_irqhandler(struct sdio_func *func)
{
- struct brcmf_sdio_card *card;
+ struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
- card = kzalloc(sizeof(struct brcmf_sdio_card), GFP_ATOMIC);
- if (card == NULL) {
- BRCMF_SD_ERROR(("sdcard_attach: out of memory"));
- return NULL;
- }
-
- /* save the handler locally */
- l_card = card;
-
- card->sdioh = brcmf_sdioh_attach(cfghdl, irq);
- if (!card->sdioh) {
- brcmf_sdcard_detach(card);
- return NULL;
- }
+ brcmf_dbg(TRACE, "***IRQHandler\n");
- card->init_success = true;
+ sdio_release_host(func);
- *regsva = SI_ENUM_BASE;
+ brcmf_sdbrcm_isr(sdiodev->bus);
- /* Report the BAR, to fix if needed */
- card->sbwad = SI_ENUM_BASE;
- return card;
+ sdio_claim_host(func);
}
-int brcmf_sdcard_detach(struct brcmf_sdio_card *card)
+int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev)
{
- if (card != NULL) {
- if (card->sdioh) {
- brcmf_sdioh_detach(card->sdioh);
- card->sdioh = NULL;
- }
- kfree(card);
- }
-
- l_card = NULL;
- return 0;
-}
+ brcmf_dbg(TRACE, "Entering\n");
-int
-brcmf_sdcard_iovar_op(struct brcmf_sdio_card *card, const char *name,
- void *params, int plen, void *arg, int len, bool set)
-{
- return brcmf_sdioh_iovar_op(card->sdioh, name, params, plen, arg,
- len, set);
-}
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler);
+ sdio_release_host(sdiodev->func[1]);
-int brcmf_sdcard_intr_enable(struct brcmf_sdio_card *card)
-{
- return brcmf_sdioh_interrupt_set(card->sdioh, true);
+ return 0;
}
-int brcmf_sdcard_intr_disable(struct brcmf_sdio_card *card)
+int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev)
{
- return brcmf_sdioh_interrupt_set(card->sdioh, false);
-}
+ brcmf_dbg(TRACE, "Entering\n");
-int brcmf_sdcard_intr_reg(struct brcmf_sdio_card *card,
- void (*fn)(void *), void *argh)
-{
- return brcmf_sdioh_interrupt_register(card->sdioh, fn, argh);
-}
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_release_irq(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
-int brcmf_sdcard_intr_dereg(struct brcmf_sdio_card *card)
-{
- return brcmf_sdioh_interrupt_deregister(card->sdioh);
+ return 0;
}
-u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_card *card, uint fnc_num, u32 addr,
+u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
int *err)
{
int status;
s32 retry = 0;
u8 data = 0;
- if (!card)
- card = l_card;
-
do {
if (retry) /* wait for 1 ms till bus get settled down */
udelay(1000);
- status =
- brcmf_sdioh_cfg_read(card->sdioh, fnc_num, addr,
- (u8 *) &data);
+ status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num,
+ addr, (u8 *) &data);
} while (status != 0
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
if (err)
*err = status;
- BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
- __func__, fnc_num, addr, data));
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
+ fnc_num, addr, data);
return data;
}
void
-brcmf_sdcard_cfg_write(struct brcmf_sdio_card *card, uint fnc_num, u32 addr,
+brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
u8 data, int *err)
{
int status;
s32 retry = 0;
- if (!card)
- card = l_card;
-
do {
if (retry) /* wait for 1 ms till bus get settled down */
udelay(1000);
- status =
- brcmf_sdioh_cfg_write(card->sdioh, fnc_num, addr,
- (u8 *) &data);
+ status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
+ addr, (u8 *) &data);
} while (status != 0
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
if (err)
*err = status;
- BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u8data = 0x%x\n",
- __func__, fnc_num, addr, data));
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
+ fnc_num, addr, data);
}
-u32 brcmf_sdcard_cfg_read_word(struct brcmf_sdio_card *card, uint fnc_num,
- u32 addr, int *err)
-{
- int status;
- u32 data = 0;
-
- if (!card)
- card = l_card;
-
- status = brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL,
- SDIOH_READ, fnc_num, addr, &data, 4);
-
- if (err)
- *err = status;
-
- BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u32data = 0x%x\n",
- __func__, fnc_num, addr, data));
-
- return data;
-}
-
-void
-brcmf_sdcard_cfg_write_word(struct brcmf_sdio_card *card, uint fnc_num,
- u32 addr, u32 data, int *err)
-{
- int status;
-
- if (!card)
- card = l_card;
-
- status =
- brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL,
- SDIOH_WRITE, fnc_num, addr, &data, 4);
-
- if (err)
- *err = status;
-
- BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, u32data = 0x%x\n",
- __func__, fnc_num, addr, data));
-}
-
-int brcmf_sdcard_cis_read(struct brcmf_sdio_card *card, uint func, u8 * cis,
- uint length)
-{
- int status;
-
- u8 *tmp_buf, *tmp_ptr;
- u8 *ptr;
- bool ascii = func & ~0xf;
- func &= 0x7;
-
- if (!card)
- card = l_card;
-
- status = brcmf_sdioh_cis_read(card->sdioh, func, cis, length);
-
- if (ascii) {
- /* Move binary bits to tmp and format them
- into the provided buffer. */
- tmp_buf = kmalloc(length, GFP_ATOMIC);
- if (tmp_buf == NULL) {
- BRCMF_SD_ERROR(("%s: out of memory\n", __func__));
- return -ENOMEM;
- }
- memcpy(tmp_buf, cis, length);
- for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4);
- tmp_ptr++) {
- ptr += sprintf((char *)ptr, "%.2x ", *tmp_ptr & 0xff);
- if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
- ptr += sprintf((char *)ptr, "\n");
- }
- kfree(tmp_buf);
- }
-
- return status;
-}
-
-static int
-brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_card *card, u32 address)
+int
+brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
{
int err = 0;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
+ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
(address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
if (!err)
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SBADDRMID,
(address >> 16) & SBSDIO_SBADDRMID_MASK,
&err);
if (!err)
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SBADDRHIGH,
(address >> 24) & SBSDIO_SBADDRHIGH_MASK,
&err);
@@ -334,34 +136,31 @@ brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_card *card, u32 address)
return err;
}
-u32 brcmf_sdcard_reg_read(struct brcmf_sdio_card *card, u32 addr, uint size)
+u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
{
int status;
u32 word = 0;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
- BRCMF_SD_INFO(("%s:fun = 1, addr = 0x%x, ", __func__, addr));
-
- if (!card)
- card = l_card;
+ brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
- if (bar0 != card->sbwad) {
- if (brcmf_sdcard_set_sbaddr_window(card, bar0))
+ if (bar0 != sdiodev->sbwad) {
+ if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
return 0xFFFFFFFF;
- card->sbwad = bar0;
+ sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
- status = brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL,
- SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
+ status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
+ addr, &word, size);
- card->regfail = (status != 0);
+ sdiodev->regfail = (status != 0);
- BRCMF_SD_INFO(("u32data = 0x%x\n", word));
+ brcmf_dbg(INFO, "u32data = 0x%x\n", word);
/* if ok, return appropriately masked word */
if (status == 0) {
@@ -373,66 +172,59 @@ u32 brcmf_sdcard_reg_read(struct brcmf_sdio_card *card, u32 addr, uint size)
case sizeof(u32):
return word;
default:
- card->regfail = true;
+ sdiodev->regfail = true;
}
}
/* otherwise, bad sdio access or invalid size */
- BRCMF_SD_ERROR(("%s: error reading addr 0x%04x size %d\n", __func__,
- addr, size));
+ brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size);
return 0xFFFFFFFF;
}
-u32 brcmf_sdcard_reg_write(struct brcmf_sdio_card *card, u32 addr, uint size,
+u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
u32 data)
{
int status;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
- BRCMF_SD_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
- __func__, addr, size * 8, data));
-
- if (!card)
- card = l_card;
+ brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
+ addr, size * 8, data);
- if (bar0 != card->sbwad) {
- err = brcmf_sdcard_set_sbaddr_window(card, bar0);
+ if (bar0 != sdiodev->sbwad) {
+ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
if (err)
return err;
- card->sbwad = bar0;
+ sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status =
- brcmf_sdioh_request_word(card->sdioh, SDIOH_CMD_TYPE_NORMAL,
- SDIOH_WRITE, SDIO_FUNC_1, addr, &data, size);
- card->regfail = (status != 0);
+ brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
+ addr, &data, size);
+ sdiodev->regfail = (status != 0);
if (status == 0)
return 0;
- BRCMF_SD_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
- __func__, data, addr, size));
+ brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n",
+ data, addr, size);
return 0xFFFFFFFF;
}
-bool brcmf_sdcard_regfail(struct brcmf_sdio_card *card)
+bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
{
- return card->regfail;
+ return sdiodev->regfail;
}
int
-brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
+brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
uint flags,
- u8 *buf, uint nbytes, struct sk_buff *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle)
+ u8 *buf, uint nbytes, struct sk_buff *pkt)
{
int status;
uint incr_fix;
@@ -440,19 +232,18 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
- BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
- __func__, fn, addr, nbytes));
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
/* Async not implemented yet */
if (flags & SDIO_REQ_ASYNC)
return -ENOTSUPP;
- if (bar0 != card->sbwad) {
- err = brcmf_sdcard_set_sbaddr_window(card, bar0);
+ if (bar0 != sdiodev->sbwad) {
+ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
if (err)
return err;
- card->sbwad = bar0;
+ sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
@@ -462,37 +253,33 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
- status = brcmf_sdioh_request_buffer(card->sdioh, SDIOH_DATA_PIO,
- incr_fix, SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
+ status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ,
+ fn, addr, width, nbytes, buf, pkt);
return status;
}
int
-brcmf_sdcard_send_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes, void *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle)
+brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt)
{
uint incr_fix;
uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
- BRCMF_SD_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
- __func__, fn, addr, nbytes));
+ brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes);
/* Async not implemented yet */
if (flags & SDIO_REQ_ASYNC)
return -ENOTSUPP;
- if (bar0 != card->sbwad) {
- err = brcmf_sdcard_set_sbaddr_window(card, bar0);
+ if (bar0 != sdiodev->sbwad) {
+ err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
if (err)
return err;
- card->sbwad = bar0;
+ sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
@@ -502,141 +289,83 @@ brcmf_sdcard_send_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
- return brcmf_sdioh_request_buffer(card->sdioh, SDIOH_DATA_PIO,
- incr_fix, SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
+ return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn,
+ addr, width, nbytes, buf, pkt);
}
-int brcmf_sdcard_rwdata(struct brcmf_sdio_card *card, uint rw, u32 addr,
+int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr,
u8 *buf, uint nbytes)
{
addr &= SBSDIO_SB_OFT_ADDR_MASK;
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
- return brcmf_sdioh_request_buffer(card->sdioh, SDIOH_DATA_PIO,
- SDIOH_DATA_INC, (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
+ return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC,
+ (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
addr, 4, nbytes, buf, NULL);
}
-int brcmf_sdcard_abort(struct brcmf_sdio_card *card, uint fn)
+int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
{
- return brcmf_sdioh_abort(card->sdioh, fn);
-}
-
-int brcmf_sdcard_query_device(struct brcmf_sdio_card *card)
-{
- card->vendevid = (PCI_VENDOR_ID_BROADCOM << 16) | 0;
- return card->vendevid;
-}
+ char t_func = (char)fn;
+ brcmf_dbg(TRACE, "Enter\n");
-u32 brcmf_sdcard_cur_sbwad(struct brcmf_sdio_card *card)
-{
- if (!card)
- card = l_card;
+ /* issue abort cmd52 command through F0 */
+ brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
+ SDIO_CCCR_ABORT, &t_func);
- return card->sbwad;
+ brcmf_dbg(TRACE, "Exit\n");
+ return 0;
}
-int brcmf_sdio_probe(struct device *dev)
+int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
{
- struct sdio_hc *sdhc = NULL;
u32 regs = 0;
- struct brcmf_sdio_card *card = NULL;
- int irq = 0;
- u32 vendevid;
- unsigned long irq_flags = 0;
-
- /* allocate SDIO Host Controller state info */
- sdhc = kzalloc(sizeof(struct sdio_hc), GFP_ATOMIC);
- if (!sdhc) {
- SDLX_MSG(("%s: out of memory\n", __func__));
- goto err;
- }
- sdhc->dev = (void *)dev;
+ int ret = 0;
- card = brcmf_sdcard_attach((void *)0, &regs, irq);
- if (!card) {
- SDLX_MSG(("%s: attach failed\n", __func__));
- goto err;
- }
+ ret = brcmf_sdioh_attach(sdiodev);
+ if (ret)
+ goto out;
- sdhc->card = card;
- sdhc->oob_irq = irq;
- sdhc->oob_flags = irq_flags;
- sdhc->oob_irq_registered = false; /* to make sure.. */
+ regs = SI_ENUM_BASE;
- /* chain SDIO Host Controller info together */
- sdhc->next = sdhcinfo;
- sdhcinfo = sdhc;
- /* Read the vendor/device ID from the CIS */
- vendevid = brcmf_sdcard_query_device(card);
+ /* Report the BAR, to fix if needed */
+ sdiodev->sbwad = SI_ENUM_BASE;
/* try to attach to the target device */
- sdhc->ch = drvinfo.attach((vendevid >> 16), (vendevid & 0xFFFF),
- 0, 0, 0, 0, regs, card);
- if (!sdhc->ch) {
- SDLX_MSG(("%s: device attach failed\n", __func__));
- goto err;
+ sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev);
+ if (!sdiodev->bus) {
+ brcmf_dbg(ERROR, "device attach failed\n");
+ ret = -ENODEV;
+ goto out;
}
- return 0;
-
- /* error handling */
-err:
- if (sdhc) {
- if (sdhc->card)
- brcmf_sdcard_detach(sdhc->card);
- kfree(sdhc);
- }
+out:
+ if (ret)
+ brcmf_sdio_remove(sdiodev);
- return -ENODEV;
+ return ret;
}
+EXPORT_SYMBOL(brcmf_sdio_probe);
-int brcmf_sdio_remove(struct device *dev)
+int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
{
- struct sdio_hc *sdhc, *prev;
-
- sdhc = sdhcinfo;
- drvinfo.detach(sdhc->ch);
- brcmf_sdcard_detach(sdhc->card);
- /* 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) {
- if (prev)
- prev->next = sdhc->next;
- else
- sdhcinfo = NULL;
- break;
- }
- prev = sdhc;
- }
- if (!sdhc) {
- SDLX_MSG(("%s: failed\n", __func__));
- return 0;
+ if (sdiodev->bus) {
+ brcmf_sdbrcm_disconnect(sdiodev->bus);
+ sdiodev->bus = NULL;
}
- /* release SDIO Host Controller info */
- kfree(sdhc);
- return 0;
-}
-
-int brcmf_sdio_register(struct brcmf_sdioh_driver *driver)
-{
- drvinfo = *driver;
+ brcmf_sdioh_detach(sdiodev);
- SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
- return brcmf_sdio_function_init();
-}
+ sdiodev->sbwad = 0;
-void brcmf_sdio_unregister(void)
-{
- brcmf_sdio_function_cleanup();
+ return 0;
}
+EXPORT_SYMBOL(brcmf_sdio_remove);
-void brcmf_sdio_wdtmr_enable(bool enable)
+void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable)
{
if (enable)
- brcmf_sdbrcm_wd_timer(sdhcinfo->ch, brcmf_watchdog_ms);
+ brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
else
- brcmf_sdbrcm_wd_timer(sdhcinfo->ch, 0);
+ brcmf_sdbrcm_wd_timer(sdiodev->bus, 0);
}
diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index 38bd9ba3096f..bbaeb2d5c93a 100644
--- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -23,6 +23,7 @@
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/sched.h> /* request_irq() */
+#include <linux/module.h>
#include <net/cfg80211.h>
#include <defs.h>
@@ -34,771 +35,179 @@
#include "dhd_dbg.h"
#include "wl_cfg80211.h"
-#define BLOCK_SIZE_64 64
-#define BLOCK_SIZE_512 512
-#define BLOCK_SIZE_4318 64
-#define BLOCK_SIZE_4328 512
-
-/* private bus modes */
-#define SDIOH_MODE_SD4 2
-
-#define CLIENT_INTR 0x100 /* Get rid of this! */
-
-#if !defined(SDIO_VENDOR_ID_BROADCOM)
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
-#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */
-
-#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000
#define DMA_ALIGN_MASK 0x03
-#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)
-#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */
-#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */
-#if !defined(SDIO_DEVICE_ID_BROADCOM_4325)
-#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493
-#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
-#if !defined(SDIO_DEVICE_ID_BROADCOM_4329)
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
-#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
-#if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
-#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319
-#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
-
-/* Common msglevel constants */
-#define SDH_ERROR_VAL 0x0001 /* Error */
-#define SDH_TRACE_VAL 0x0002 /* Trace */
-#define SDH_INFO_VAL 0x0004 /* Info */
-#define SDH_DEBUG_VAL 0x0008 /* Debug */
-#define SDH_DATA_VAL 0x0010 /* Data */
-#define SDH_CTRL_VAL 0x0020 /* Control Regs */
-#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */
-#define SDH_DMA_VAL 0x0080 /* DMA */
-
-#ifdef BCMDBG
-#define sd_err(x) \
- do { \
- if ((sd_msglevel & SDH_ERROR_VAL) && net_ratelimit()) \
- printk x; \
- } while (0)
-#define sd_trace(x) \
- do { \
- if ((sd_msglevel & SDH_TRACE_VAL) && net_ratelimit()) \
- printk x; \
- } while (0)
-#define sd_info(x) \
- do { \
- if ((sd_msglevel & SDH_INFO_VAL) && net_ratelimit()) \
- printk x; \
- } while (0)
-#define sd_debug(x) \
- do { \
- if ((sd_msglevel & SDH_DEBUG_VAL) && net_ratelimit()) \
- printk x; \
- } while (0)
-#define sd_data(x) \
- do { \
- if ((sd_msglevel & SDH_DATA_VAL) && net_ratelimit()) \
- printk x; \
- } while (0)
-#define sd_ctrl(x) \
- do { \
- if ((sd_msglevel & SDH_CTRL_VAL) && net_ratelimit()) \
- printk x; \
- } while (0)
-#else
-#define sd_err(x)
-#define sd_trace(x)
-#define sd_info(x)
-#define sd_debug(x)
-#define sd_data(x)
-#define sd_ctrl(x)
-#endif
-
-struct sdos_info {
- struct sdioh_info *sd;
- spinlock_t lock;
-};
-
-static void brcmf_sdioh_irqhandler(struct sdio_func *func);
-static void brcmf_sdioh_irqhandler_f2(struct sdio_func *func);
-static int brcmf_sdioh_get_cisaddr(struct sdioh_info *sd, u32 regaddr);
-static int brcmf_ops_sdio_probe(struct sdio_func *func,
- const struct sdio_device_id *id);
-static void brcmf_ops_sdio_remove(struct sdio_func *func);
-
-#ifdef CONFIG_PM
-static int brcmf_sdio_suspend(struct device *dev);
-static int brcmf_sdio_resume(struct device *dev);
-#endif /* CONFIG_PM */
-uint sd_f2_blocksize = 512; /* Default blocksize */
-
-uint sd_msglevel = 0x01;
-
-/* module param defaults */
-static int clockoverride;
-
-module_param(clockoverride, int, 0644);
-MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
-
-struct brcmf_sdmmc_instance *gInstance;
-
-struct device sdmmc_dev;
+#define SDIO_FUNC1_BLOCKSIZE 64
+#define SDIO_FUNC2_BLOCKSIZE 512
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT)},
- {SDIO_DEVICE
- (SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
- {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319)},
{ /* end: all zeroes */ },
};
-
-#ifdef CONFIG_PM
-static const struct dev_pm_ops brcmf_sdio_pm_ops = {
- .suspend = brcmf_sdio_suspend,
- .resume = brcmf_sdio_resume,
-};
-#endif /* CONFIG_PM */
-
-static struct sdio_driver brcmf_sdmmc_driver = {
- .probe = brcmf_ops_sdio_probe,
- .remove = brcmf_ops_sdio_remove,
- .name = "brcmfmac",
- .id_table = brcmf_sdmmc_ids,
-#ifdef CONFIG_PM
- .drv = {
- .pm = &brcmf_sdio_pm_ops,
- },
-#endif /* CONFIG_PM */
-};
-
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
-BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
-BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
-BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
-BRCMF_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
-
-static int
-brcmf_sdioh_card_regread(struct sdioh_info *sd, int func, u32 regaddr,
- int regsize, u32 *data);
-
-static int brcmf_sdioh_enablefuncs(struct sdioh_info *sd)
+static bool
+brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
{
- int err_ret;
- u32 fbraddr;
- u8 func;
-
- sd_trace(("%s\n", __func__));
-
- /* Get the Card's common CIS address */
- sd->com_cis_ptr = brcmf_sdioh_get_cisaddr(sd, SDIO_CCCR_CIS);
- sd->func_cis_ptr[0] = sd->com_cis_ptr;
- sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
- sd->com_cis_ptr));
-
- /* Get the Card's function CIS (for each function) */
- for (fbraddr = SDIO_FBR_BASE(1), func = 1;
- func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
- sd->func_cis_ptr[func] =
- brcmf_sdioh_get_cisaddr(sd, SDIO_FBR_CIS + fbraddr);
- sd_info(("%s: Function %d CIS Ptr = 0x%x\n", __func__, func,
- sd->func_cis_ptr[func]));
- }
-
- sd->func_cis_ptr[0] = sd->com_cis_ptr;
- sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __func__,
- sd->com_cis_ptr));
-
- /* Enable Function 1 */
- sdio_claim_host(gInstance->func[1]);
- err_ret = sdio_enable_func(gInstance->func[1]);
- sdio_release_host(gInstance->func[1]);
- if (err_ret) {
- sd_err(("brcmf_sdioh_enablefuncs: Failed to enable F1 "
- "Err: 0x%08x\n", err_ret));
- }
-
- return false;
-}
-
-/*
- * Public entry points & extern's
- */
-struct sdioh_info *brcmf_sdioh_attach(void *bar0, uint irq)
-{
- struct sdioh_info *sd;
- int err_ret;
-
- sd_trace(("%s\n", __func__));
-
- if (gInstance == NULL) {
- sd_err(("%s: SDIO Device not present\n", __func__));
- return NULL;
- }
-
- sd = kzalloc(sizeof(struct sdioh_info), GFP_ATOMIC);
- if (sd == NULL) {
- sd_err(("sdioh_attach: out of memory\n"));
- return NULL;
- }
- if (brcmf_sdioh_osinit(sd) != 0) {
- sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __func__));
- kfree(sd);
- return NULL;
- }
-
- sd->num_funcs = 2;
- sd->use_client_ints = true;
- sd->client_block_size[0] = 64;
-
- gInstance->sd = sd;
-
- /* Claim host controller */
- sdio_claim_host(gInstance->func[1]);
-
- sd->client_block_size[1] = 64;
- err_ret = sdio_set_block_size(gInstance->func[1], 64);
- if (err_ret)
- sd_err(("brcmf_sdioh_attach: Failed to set F1 blocksize\n"));
-
- /* Release host controller F1 */
- sdio_release_host(gInstance->func[1]);
-
- if (gInstance->func[2]) {
- /* Claim host controller F2 */
- sdio_claim_host(gInstance->func[2]);
-
- sd->client_block_size[2] = sd_f2_blocksize;
- err_ret =
- sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
- if (err_ret)
- sd_err(("brcmf_sdioh_attach: Failed to set F2 blocksize"
- " to %d\n", sd_f2_blocksize));
-
- /* Release host controller F2 */
- sdio_release_host(gInstance->func[2]);
- }
-
- brcmf_sdioh_enablefuncs(sd);
-
- sd_trace(("%s: Done\n", __func__));
- return sd;
-}
-
-extern int brcmf_sdioh_detach(struct sdioh_info *sd)
-{
- sd_trace(("%s\n", __func__));
-
- if (sd) {
-
- /* Disable Function 2 */
- sdio_claim_host(gInstance->func[2]);
- sdio_disable_func(gInstance->func[2]);
- sdio_release_host(gInstance->func[2]);
-
- /* Disable Function 1 */
- sdio_claim_host(gInstance->func[1]);
- sdio_disable_func(gInstance->func[1]);
- sdio_release_host(gInstance->func[1]);
-
- /* deregister irq */
- brcmf_sdioh_osfree(sd);
-
- kfree(sd);
- }
- return 0;
-}
-
-/* Configure callback to client when we receive client interrupt */
-extern int
-brcmf_sdioh_interrupt_register(struct sdioh_info *sd, void (*fn)(void *),
- void *argh)
-{
- sd_trace(("%s: Entering\n", __func__));
- if (fn == NULL) {
- sd_err(("%s: interrupt handler is NULL, not registering\n",
- __func__));
- return -EINVAL;
- }
-
- sd->intr_handler = fn;
- sd->intr_handler_arg = argh;
- sd->intr_handler_valid = true;
-
- /* register and unmask irq */
- if (gInstance->func[2]) {
- sdio_claim_host(gInstance->func[2]);
- sdio_claim_irq(gInstance->func[2], brcmf_sdioh_irqhandler_f2);
- sdio_release_host(gInstance->func[2]);
- }
-
- if (gInstance->func[1]) {
- sdio_claim_host(gInstance->func[1]);
- sdio_claim_irq(gInstance->func[1], brcmf_sdioh_irqhandler);
- sdio_release_host(gInstance->func[1]);
- }
-
- return 0;
+ bool is_err = false;
+#ifdef CONFIG_PM_SLEEP
+ is_err = atomic_read(&sdiodev->suspend);
+#endif
+ return is_err;
}
-extern int brcmf_sdioh_interrupt_deregister(struct sdioh_info *sd)
+static void
+brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq)
{
- sd_trace(("%s: Entering\n", __func__));
-
- if (gInstance->func[1]) {
- /* register and unmask irq */
- sdio_claim_host(gInstance->func[1]);
- sdio_release_irq(gInstance->func[1]);
- sdio_release_host(gInstance->func[1]);
- }
-
- if (gInstance->func[2]) {
- /* Claim host controller F2 */
- sdio_claim_host(gInstance->func[2]);
- sdio_release_irq(gInstance->func[2]);
- /* Release host controller F2 */
- sdio_release_host(gInstance->func[2]);
- }
-
- sd->intr_handler_valid = false;
- sd->intr_handler = NULL;
- sd->intr_handler_arg = NULL;
-
- return 0;
+#ifdef CONFIG_PM_SLEEP
+ int retry = 0;
+ while (atomic_read(&sdiodev->suspend) && retry++ != 30)
+ wait_event_timeout(*wq, false, HZ/100);
+#endif
}
-/* IOVar table */
-enum {
- IOV_MSGLEVEL = 1,
- IOV_BLOCKSIZE,
- IOV_USEINTS,
- IOV_NUMINTS,
- IOV_DEVREG,
- IOV_HCIREGS,
- IOV_RXCHAIN
-};
-
-const struct brcmu_iovar sdioh_iovars[] = {
- {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0},
- {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0},/* ((fn << 16) |
- size) */
- {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0},
- {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0},
- {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)}
- ,
- {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0}
- ,
- {NULL, 0, 0, 0, 0}
-};
-
-int
-brcmf_sdioh_iovar_op(struct sdioh_info *si, const char *name,
- void *params, int plen, void *arg, int len, bool set)
+static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev,
+ uint regaddr, u8 *byte)
{
- const struct brcmu_iovar *vi = NULL;
- int bcmerror = 0;
- int val_size;
- s32 int_val = 0;
- bool bool_val;
- u32 actionid;
-
- if (name == NULL || len <= 0)
- return -EINVAL;
-
- /* Set does not take qualifiers */
- if (set && (params || plen))
- return -EINVAL;
-
- /* Get must have return space;*/
- if (!set && !(arg && len))
- return -EINVAL;
-
- sd_trace(("%s: Enter (%s %s)\n", __func__, (set ? "set" : "get"),
- name));
-
- vi = brcmu_iovar_lookup(sdioh_iovars, name);
- if (vi == NULL) {
- bcmerror = -ENOTSUPP;
- goto exit;
- }
-
- bcmerror = brcmu_iovar_lencheck(vi, arg, len, set);
- if (bcmerror != 0)
- goto exit;
-
- /* Set up params so get and set can share the convenience variables */
- if (params == NULL) {
- params = arg;
- plen = len;
- }
-
- if (vi->type == IOVT_VOID)
- val_size = 0;
- else if (vi->type == IOVT_BUFFER)
- val_size = len;
- else
- val_size = sizeof(int);
-
- if (plen >= (int)sizeof(int_val))
- memcpy(&int_val, params, sizeof(int_val));
-
- bool_val = (int_val != 0) ? true : false;
-
- actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
- switch (actionid) {
- case IOV_GVAL(IOV_MSGLEVEL):
- int_val = (s32) sd_msglevel;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_MSGLEVEL):
- sd_msglevel = int_val;
- break;
-
- case IOV_GVAL(IOV_BLOCKSIZE):
- if ((u32) int_val > si->num_funcs) {
- bcmerror = -EINVAL;
- break;
- }
- int_val = (s32) si->client_block_size[int_val];
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_BLOCKSIZE):
- {
- uint func = ((u32) int_val >> 16);
- uint blksize = (u16) int_val;
- uint maxsize;
-
- if (func > si->num_funcs) {
- bcmerror = -EINVAL;
- break;
- }
-
- switch (func) {
- case 0:
- maxsize = 32;
- break;
- case 1:
- maxsize = BLOCK_SIZE_4318;
- break;
- case 2:
- maxsize = BLOCK_SIZE_4328;
- break;
- default:
- maxsize = 0;
- }
- if (blksize > maxsize) {
- bcmerror = -EINVAL;
- break;
- }
- if (!blksize)
- blksize = maxsize;
-
- /* Now set it */
- si->client_block_size[func] = blksize;
-
- break;
- }
-
- case IOV_GVAL(IOV_RXCHAIN):
- int_val = false;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_GVAL(IOV_USEINTS):
- int_val = (s32) si->use_client_ints;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_USEINTS):
- si->use_client_ints = (bool) int_val;
- if (si->use_client_ints)
- si->intmask |= CLIENT_INTR;
- else
- si->intmask &= ~CLIENT_INTR;
-
- break;
-
- case IOV_GVAL(IOV_NUMINTS):
- int_val = (s32) si->intrcount;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_GVAL(IOV_DEVREG):
- {
- struct brcmf_sdreg *sd_ptr =
- (struct brcmf_sdreg *) params;
- u8 data = 0;
-
- if (brcmf_sdioh_cfg_read
- (si, sd_ptr->func, sd_ptr->offset, &data)) {
- bcmerror = -EIO;
- break;
- }
-
- int_val = (int)data;
- memcpy(arg, &int_val, sizeof(int_val));
- break;
- }
-
- case IOV_SVAL(IOV_DEVREG):
- {
- struct brcmf_sdreg *sd_ptr =
- (struct brcmf_sdreg *) params;
- u8 data = (u8) sd_ptr->value;
+ struct sdio_func *sdfunc = sdiodev->func[0];
+ int err_ret;
- if (brcmf_sdioh_cfg_write
- (si, sd_ptr->func, sd_ptr->offset, &data)) {
- bcmerror = -EIO;
- break;
+ /*
+ * Can only directly write to some F0 registers.
+ * Handle F2 enable/disable and Abort command
+ * as a special case.
+ */
+ if (regaddr == SDIO_CCCR_IOEx) {
+ sdfunc = sdiodev->func[2];
+ if (sdfunc) {
+ sdio_claim_host(sdfunc);
+ if (*byte & SDIO_FUNC_ENABLE_2) {
+ /* Enable Function 2 */
+ err_ret = sdio_enable_func(sdfunc);
+ if (err_ret)
+ brcmf_dbg(ERROR,
+ "enable F2 failed:%d\n",
+ err_ret);
+ } else {
+ /* Disable Function 2 */
+ err_ret = sdio_disable_func(sdfunc);
+ if (err_ret)
+ brcmf_dbg(ERROR,
+ "Disable F2 failed:%d\n",
+ err_ret);
}
- break;
- }
-
- default:
- bcmerror = -ENOTSUPP;
- break;
- }
-exit:
-
- return bcmerror;
-}
-
-extern int
-brcmf_sdioh_cfg_read(struct sdioh_info *sd, uint fnc_num, u32 addr, u8 *data)
-{
- int status;
- /* No lock needed since brcmf_sdioh_request_byte does locking */
- status = brcmf_sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
- return status;
-}
-
-extern int
-brcmf_sdioh_cfg_write(struct sdioh_info *sd, uint fnc_num, u32 addr, u8 *data)
-{
- /* No lock needed since brcmf_sdioh_request_byte does locking */
- int status;
- status = brcmf_sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
- return status;
-}
-
-static int brcmf_sdioh_get_cisaddr(struct sdioh_info *sd, u32 regaddr)
-{
- /* read 24 bits and return valid 17 bit addr */
- int i;
- u32 scratch, regdata;
- u8 *ptr = (u8 *)&scratch;
- for (i = 0; i < 3; i++) {
- if ((brcmf_sdioh_card_regread(sd, 0, regaddr, 1, &regdata)) !=
- SUCCESS)
- sd_err(("%s: Can't read!\n", __func__));
-
- *ptr++ = (u8) regdata;
- regaddr++;
- }
-
- /* Only the lower 17-bits are valid */
- scratch = le32_to_cpu(scratch);
- scratch &= 0x0001FFFF;
- return scratch;
-}
-
-extern int
-brcmf_sdioh_cis_read(struct sdioh_info *sd, uint func, u8 *cisd, u32 length)
-{
- u32 count;
- int offset;
- u32 foo;
- u8 *cis = cisd;
-
- sd_trace(("%s: Func = %d\n", __func__, func));
-
- if (!sd->func_cis_ptr[func]) {
- memset(cis, 0, length);
- sd_err(("%s: no func_cis_ptr[%d]\n", __func__, func));
- return -ENOTSUPP;
- }
-
- sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __func__, func,
- sd->func_cis_ptr[func]));
-
- for (count = 0; count < length; count++) {
- offset = sd->func_cis_ptr[func] + count;
- if (brcmf_sdioh_card_regread(sd, 0, offset, 1, &foo) < 0) {
- sd_err(("%s: regread failed: Can't read CIS\n",
- __func__));
- return -EIO;
+ sdio_release_host(sdfunc);
}
-
- *cis = (u8) (foo & 0xff);
- cis++;
+ } else if (regaddr == SDIO_CCCR_ABORT) {
+ sdio_claim_host(sdfunc);
+ sdio_writeb(sdfunc, *byte, regaddr, &err_ret);
+ sdio_release_host(sdfunc);
+ } else if (regaddr < 0xF0) {
+ brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr);
+ err_ret = -EPERM;
+ } else {
+ sdio_claim_host(sdfunc);
+ sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret);
+ sdio_release_host(sdfunc);
}
- return 0;
+ return err_ret;
}
-extern int
-brcmf_sdioh_request_byte(struct sdioh_info *sd, uint rw, uint func,
- uint regaddr, u8 *byte)
+int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func,
+ uint regaddr, u8 *byte)
{
int err_ret;
- sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __func__, rw, func,
- regaddr));
+ brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
- BRCMF_PM_RESUME_WAIT(sdioh_request_byte_wait);
- BRCMF_PM_RESUME_RETURN_ERROR(-EIO);
- if (rw) { /* CMD52 Write */
- if (func == 0) {
- /* Can only directly write to some F0 registers.
- * Handle F2 enable
- * as a special case.
- */
- if (regaddr == SDIO_CCCR_IOEx) {
- if (gInstance->func[2]) {
- sdio_claim_host(gInstance->func[2]);
- if (*byte & SDIO_FUNC_ENABLE_2) {
- /* Enable Function 2 */
- err_ret =
- sdio_enable_func
- (gInstance->func[2]);
- if (err_ret)
- sd_err(("request_byte: "
- "enable F2 "
- "failed:%d\n",
- err_ret));
- } else {
- /* Disable Function 2 */
- err_ret =
- sdio_disable_func
- (gInstance->func[2]);
- if (err_ret)
- sd_err(("request_byte: "
- "Disab F2 "
- "failed:%d\n",
- err_ret));
- }
- sdio_release_host(gInstance->func[2]);
- }
- }
- /* to allow abort command through F1 */
- else if (regaddr == SDIO_CCCR_ABORT) {
- sdio_claim_host(gInstance->func[func]);
- /*
- * this sdio_f0_writeb() can be replaced
- * with another api
- * depending upon MMC driver change.
- * As of this time, this is temporaray one
- */
- sdio_writeb(gInstance->func[func], *byte,
- regaddr, &err_ret);
- sdio_release_host(gInstance->func[func]);
- } else if (regaddr < 0xF0) {
- sd_err(("brcmf: F0 Wr:0x%02x: write "
- "disallowed\n", regaddr));
- } else {
- /* Claim host controller, perform F0 write,
- and release */
- sdio_claim_host(gInstance->func[func]);
- sdio_f0_writeb(gInstance->func[func], *byte,
- regaddr, &err_ret);
- sdio_release_host(gInstance->func[func]);
- }
- } else {
- /* Claim host controller, perform Fn write,
- and release */
- sdio_claim_host(gInstance->func[func]);
- sdio_writeb(gInstance->func[func], *byte, regaddr,
- &err_ret);
- sdio_release_host(gInstance->func[func]);
- }
- } else { /* CMD52 Read */
- /* Claim host controller, perform Fn read, and release */
- sdio_claim_host(gInstance->func[func]);
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
- if (func == 0) {
- *byte =
- sdio_f0_readb(gInstance->func[func], regaddr,
- &err_ret);
+ if (rw && func == 0) {
+ /* handle F0 separately */
+ err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte);
+ } else {
+ sdio_claim_host(sdiodev->func[func]);
+ if (rw) /* CMD52 Write */
+ sdio_writeb(sdiodev->func[func], *byte, regaddr,
+ &err_ret);
+ else if (func == 0) {
+ *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
+ &err_ret);
} else {
- *byte =
- sdio_readb(gInstance->func[func], regaddr,
- &err_ret);
+ *byte = sdio_readb(sdiodev->func[func], regaddr,
+ &err_ret);
}
-
- sdio_release_host(gInstance->func[func]);
+ sdio_release_host(sdiodev->func[func]);
}
if (err_ret)
- sd_err(("brcmf: Failed to %s byte F%d:@0x%05x=%02x, "
- "Err: %d\n", rw ? "Write" : "Read", func, regaddr,
- *byte, err_ret));
+ brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
+ rw ? "write" : "read", func, regaddr, *byte, err_ret);
return err_ret;
}
-extern int
-brcmf_sdioh_request_word(struct sdioh_info *sd, uint cmd_type, uint rw,
- uint func, uint addr, u32 *word, uint nbytes)
+int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
+ uint rw, uint func, uint addr, u32 *word,
+ uint nbytes)
{
int err_ret = -EIO;
if (func == 0) {
- sd_err(("%s: Only CMD52 allowed to F0.\n", __func__));
+ brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n");
return -EINVAL;
}
- sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
- __func__, cmd_type, rw, func, addr, nbytes));
+ brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+ rw, func, addr, nbytes);
- BRCMF_PM_RESUME_WAIT(sdioh_request_word_wait);
- BRCMF_PM_RESUME_RETURN_ERROR(-EIO);
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
/* Claim host controller */
- sdio_claim_host(gInstance->func[func]);
+ sdio_claim_host(sdiodev->func[func]);
if (rw) { /* CMD52 Write */
- if (nbytes == 4) {
- sdio_writel(gInstance->func[func], *word, addr,
+ if (nbytes == 4)
+ sdio_writel(sdiodev->func[func], *word, addr,
&err_ret);
- } else if (nbytes == 2) {
- sdio_writew(gInstance->func[func], (*word & 0xFFFF),
+ else if (nbytes == 2)
+ sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
addr, &err_ret);
- } else {
- sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
- }
+ else
+ brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
} else { /* CMD52 Read */
- if (nbytes == 4) {
- *word =
- sdio_readl(gInstance->func[func], addr, &err_ret);
- } else if (nbytes == 2) {
- *word =
- sdio_readw(gInstance->func[func], addr,
- &err_ret) & 0xFFFF;
- } else {
- sd_err(("%s: Invalid nbytes: %d\n", __func__, nbytes));
- }
+ if (nbytes == 4)
+ *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
+ else if (nbytes == 2)
+ *word = sdio_readw(sdiodev->func[func], addr,
+ &err_ret) & 0xFFFF;
+ else
+ brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes);
}
/* Release host controller */
- sdio_release_host(gInstance->func[func]);
+ sdio_release_host(sdiodev->func[func]);
- if (err_ret) {
- sd_err(("brcmf: Failed to %s word, Err: 0x%08x\n",
- rw ? "Write" : "Read", err_ret));
- }
+ if (err_ret)
+ brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n",
+ rw ? "write" : "read", err_ret);
return err_ret;
}
static int
-brcmf_sdioh_request_packet(struct sdioh_info *sd, uint fix_inc, uint write,
- uint func, uint addr, struct sk_buff *pkt)
+brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc,
+ uint write, uint func, uint addr,
+ struct sk_buff *pkt)
{
bool fifo = (fix_inc == SDIOH_DATA_FIX);
u32 SGCount = 0;
@@ -806,46 +215,45 @@ brcmf_sdioh_request_packet(struct sdioh_info *sd, uint fix_inc, uint write,
struct sk_buff *pnext;
- sd_trace(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- BRCMF_PM_RESUME_WAIT(sdioh_request_packet_wait);
- BRCMF_PM_RESUME_RETURN_ERROR(-EIO);
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
/* Claim host controller */
- sdio_claim_host(gInstance->func[func]);
+ sdio_claim_host(sdiodev->func[func]);
for (pnext = pkt; pnext; pnext = pnext->next) {
uint pkt_len = pnext->len;
pkt_len += 3;
pkt_len &= 0xFFFFFFFC;
if ((write) && (!fifo)) {
- err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
+ err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pnext->data)),
pkt_len);
} else if (write) {
- err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
+ err_ret = sdio_memcpy_toio(sdiodev->func[func], addr,
((u8 *) (pnext->data)),
pkt_len);
} else if (fifo) {
- err_ret = sdio_readsb(gInstance->func[func],
+ err_ret = sdio_readsb(sdiodev->func[func],
((u8 *) (pnext->data)),
addr, pkt_len);
} else {
- err_ret = sdio_memcpy_fromio(gInstance->func[func],
+ err_ret = sdio_memcpy_fromio(sdiodev->func[func],
((u8 *) (pnext->data)),
addr, pkt_len);
}
if (err_ret) {
- sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d,"
- "ERR=0x%08x\n", __func__,
- (write) ? "TX" : "RX",
- pnext, SGCount, addr, pkt_len, err_ret));
+ brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
+ 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",
- __func__,
- (write) ? "TX" : "RX",
- pnext, SGCount, addr, pkt_len));
+ brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n",
+ write ? "TX" : "RX", pnext, SGCount, addr,
+ pkt_len);
}
if (!fifo)
@@ -855,9 +263,9 @@ brcmf_sdioh_request_packet(struct sdioh_info *sd, uint fix_inc, uint write,
}
/* Release host controller */
- sdio_release_host(gInstance->func[func]);
+ sdio_release_host(sdiodev->func[func]);
- sd_trace(("%s: Exit\n", __func__));
+ brcmf_dbg(TRACE, "Exit\n");
return err_ret;
}
@@ -876,26 +284,27 @@ brcmf_sdioh_request_packet(struct sdioh_info *sd, uint fix_inc, uint write,
* aligned packet.
*
*/
-extern int
-brcmf_sdioh_request_buffer(struct sdioh_info *sd, uint pio_dma, uint fix_inc,
- uint write, uint func, uint addr, uint reg_width,
- uint buflen_u, u8 *buffer, struct sk_buff *pkt)
+int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
+ uint fix_inc, uint write, uint func, uint addr,
+ uint reg_width, uint buflen_u, u8 *buffer,
+ struct sk_buff *pkt)
{
int Status;
struct sk_buff *mypkt = NULL;
- sd_trace(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- BRCMF_PM_RESUME_WAIT(sdioh_request_buffer_wait);
- BRCMF_PM_RESUME_RETURN_ERROR(-EIO);
+ brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
+ if (brcmf_pm_resume_error(sdiodev))
+ return -EIO;
/* Case 1: we don't have a packet. */
if (pkt == NULL) {
- sd_data(("%s: Creating new %s Packet, len=%d\n",
- __func__, write ? "TX" : "RX", buflen_u));
+ brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n",
+ write ? "TX" : "RX", buflen_u);
mypkt = brcmu_pkt_buf_get_skb(buflen_u);
if (!mypkt) {
- sd_err(("%s: brcmu_pkt_buf_get_skb failed: len %d\n",
- __func__, buflen_u));
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+ buflen_u);
return -EIO;
}
@@ -903,8 +312,8 @@ brcmf_sdioh_request_buffer(struct sdioh_info *sd, uint pio_dma, uint fix_inc,
if (write)
memcpy(mypkt->data, buffer, buflen_u);
- Status = brcmf_sdioh_request_packet(sd, fix_inc, write, func,
- addr, mypkt);
+ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
+ func, addr, mypkt);
/* For a read, copy the packet data back to the buffer. */
if (!write)
@@ -916,12 +325,12 @@ brcmf_sdioh_request_buffer(struct sdioh_info *sd, uint pio_dma, uint fix_inc,
* Case 2: We have a packet, but it is unaligned.
* In this case, we cannot have a chain (pkt->next == NULL)
*/
- sd_data(("%s: Creating aligned %s Packet, len=%d\n",
- __func__, write ? "TX" : "RX", pkt->len));
+ brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n",
+ write ? "TX" : "RX", pkt->len);
mypkt = brcmu_pkt_buf_get_skb(pkt->len);
if (!mypkt) {
- sd_err(("%s: brcmu_pkt_buf_get_skb failed: len %d\n",
- __func__, pkt->len));
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n",
+ pkt->len);
return -EIO;
}
@@ -929,8 +338,8 @@ brcmf_sdioh_request_buffer(struct sdioh_info *sd, uint pio_dma, uint fix_inc,
if (write)
memcpy(mypkt->data, pkt->data, pkt->len);
- Status = brcmf_sdioh_request_packet(sd, fix_inc, write, func,
- addr, mypkt);
+ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
+ func, addr, mypkt);
/* For a read, copy the packet data back to the buffer. */
if (!write)
@@ -939,128 +348,185 @@ brcmf_sdioh_request_buffer(struct sdioh_info *sd, uint pio_dma, uint fix_inc,
brcmu_pkt_buf_free_skb(mypkt);
} else { /* case 3: We have a packet and
it is aligned. */
- sd_data(("%s: Aligned %s Packet, direct DMA\n",
- __func__, write ? "Tx" : "Rx"));
- Status = brcmf_sdioh_request_packet(sd, fix_inc, write, func,
- addr, pkt);
+ brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n",
+ write ? "Tx" : "Rx");
+ Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write,
+ func, addr, pkt);
}
return Status;
}
-/* this function performs "abort" for both of host & device */
-extern int brcmf_sdioh_abort(struct sdioh_info *sd, uint func)
-{
- char t_func = (char)func;
- sd_trace(("%s: Enter\n", __func__));
-
- /* issue abort cmd52 command through F0 */
- brcmf_sdioh_request_byte(sd, SDIOH_WRITE, SDIO_FUNC_0, SDIO_CCCR_ABORT,
- &t_func);
-
- sd_trace(("%s: Exit\n", __func__));
- return 0;
-}
-
-/* Disable device interrupt */
-void brcmf_sdioh_dev_intr_off(struct sdioh_info *sd)
-{
- sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
- sd->intmask &= ~CLIENT_INTR;
-}
-
-/* Enable device interrupt */
-void brcmf_sdioh_dev_intr_on(struct sdioh_info *sd)
-{
- sd_trace(("%s: %d\n", __func__, sd->use_client_ints));
- sd->intmask |= CLIENT_INTR;
-}
-
/* Read client card reg */
-int
-brcmf_sdioh_card_regread(struct sdioh_info *sd, int func, u32 regaddr,
+static int
+brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr,
int regsize, u32 *data)
{
if ((func == 0) || (regsize == 1)) {
u8 temp = 0;
- brcmf_sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
+ brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr,
+ &temp);
*data = temp;
*data &= 0xff;
- sd_data(("%s: byte read data=0x%02x\n", __func__, *data));
+ brcmf_dbg(DATA, "byte read data=0x%02x\n", *data);
} else {
- brcmf_sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data,
- regsize);
+ brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr,
+ data, regsize);
if (regsize == 2)
*data &= 0xffff;
- sd_data(("%s: word read data=0x%08x\n", __func__, *data));
+ brcmf_dbg(DATA, "word read data=0x%08x\n", *data);
}
return SUCCESS;
}
-static void brcmf_sdioh_irqhandler(struct sdio_func *func)
+static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
{
- struct sdioh_info *sd;
+ /* read 24 bits and return valid 17 bit addr */
+ int i;
+ u32 scratch, regdata;
+ __le32 scratch_le;
+ u8 *ptr = (u8 *)&scratch_le;
- sd_trace(("brcmf: ***IRQHandler\n"));
- sd = gInstance->sd;
+ for (i = 0; i < 3; i++) {
+ if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1,
+ &regdata)) != SUCCESS)
+ brcmf_dbg(ERROR, "Can't read!\n");
- sdio_release_host(gInstance->func[0]);
+ *ptr++ = (u8) regdata;
+ regaddr++;
+ }
- if (sd->use_client_ints) {
- sd->intrcount++;
- (sd->intr_handler) (sd->intr_handler_arg);
- } else {
- sd_err(("brcmf: ***IRQHandler\n"));
+ /* Only the lower 17-bits are valid */
+ scratch = le32_to_cpu(scratch_le);
+ scratch &= 0x0001FFFF;
+ return scratch;
+}
- sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
- __func__, sd->client_intr_enabled, sd->intr_handler));
+static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
+{
+ int err_ret;
+ u32 fbraddr;
+ u8 func;
+
+ brcmf_dbg(TRACE, "\n");
+
+ /* Get the Card's common CIS address */
+ sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev,
+ SDIO_CCCR_CIS);
+ brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n",
+ sdiodev->func_cis_ptr[0]);
+
+ /* Get the Card's function CIS (for each function) */
+ for (fbraddr = SDIO_FBR_BASE(1), func = 1;
+ func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
+ sdiodev->func_cis_ptr[func] =
+ brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr);
+ brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n",
+ func, sdiodev->func_cis_ptr[func]);
+ }
+
+ /* Enable Function 1 */
+ sdio_claim_host(sdiodev->func[1]);
+ err_ret = sdio_enable_func(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
+ if (err_ret)
+ brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret);
+
+ return false;
+}
+
+/*
+ * Public entry points & extern's
+ */
+int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
+{
+ int err_ret = 0;
+
+ brcmf_dbg(TRACE, "\n");
+
+ sdiodev->num_funcs = 2;
+
+ sdio_claim_host(sdiodev->func[1]);
+ err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
+ sdio_release_host(sdiodev->func[1]);
+ if (err_ret) {
+ brcmf_dbg(ERROR, "Failed to set F1 blocksize\n");
+ goto out;
+ }
+
+ sdio_claim_host(sdiodev->func[2]);
+ err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
+ sdio_release_host(sdiodev->func[2]);
+ if (err_ret) {
+ brcmf_dbg(ERROR, "Failed to set F2 blocksize\n");
+ goto out;
}
- sdio_claim_host(gInstance->func[0]);
+ brcmf_sdioh_enablefuncs(sdiodev);
+
+out:
+ brcmf_dbg(TRACE, "Done\n");
+ return err_ret;
}
-/* interrupt handler for F2 (dummy handler) */
-static void brcmf_sdioh_irqhandler_f2(struct sdio_func *func)
+void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev)
{
- struct sdioh_info *sd;
+ brcmf_dbg(TRACE, "\n");
+
+ /* Disable Function 2 */
+ sdio_claim_host(sdiodev->func[2]);
+ sdio_disable_func(sdiodev->func[2]);
+ sdio_release_host(sdiodev->func[2]);
- sd_trace(("brcmf: ***IRQHandlerF2\n"));
+ /* Disable Function 1 */
+ sdio_claim_host(sdiodev->func[1]);
+ sdio_disable_func(sdiodev->func[1]);
+ sdio_release_host(sdiodev->func[1]);
- sd = gInstance->sd;
}
static int brcmf_ops_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int ret = 0;
- static struct sdio_func sdio_func_0;
- sd_trace(("sdio_probe: %s Enter\n", __func__));
- sd_trace(("sdio_probe: func->class=%x\n", func->class));
- sd_trace(("sdio_vendor: 0x%04x\n", func->vendor));
- sd_trace(("sdio_device: 0x%04x\n", func->device));
- sd_trace(("Function#: 0x%04x\n", func->num));
+ struct brcmf_sdio_dev *sdiodev;
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(TRACE, "func->class=%x\n", func->class);
+ brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
+ brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device);
+ brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num);
if (func->num == 1) {
- sdio_func_0.num = 0;
- sdio_func_0.card = func->card;
- gInstance->func[0] = &sdio_func_0;
- if (func->device == 0x4) { /* 4318 */
- gInstance->func[2] = NULL;
- sd_trace(("NIC found, calling brcmf_sdio_probe...\n"));
- ret = brcmf_sdio_probe(&sdmmc_dev);
+ if (dev_get_drvdata(&func->card->dev)) {
+ brcmf_dbg(ERROR, "card private drvdata occupied\n");
+ return -ENXIO;
}
- }
+ sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
+ if (!sdiodev)
+ return -ENOMEM;
+ sdiodev->func[0] = func->card->sdio_func[0];
+ sdiodev->func[1] = func;
+ dev_set_drvdata(&func->card->dev, sdiodev);
- gInstance->func[func->num] = func;
+ atomic_set(&sdiodev->suspend, false);
+ init_waitqueue_head(&sdiodev->request_byte_wait);
+ init_waitqueue_head(&sdiodev->request_word_wait);
+ init_waitqueue_head(&sdiodev->request_packet_wait);
+ init_waitqueue_head(&sdiodev->request_buffer_wait);
+ }
if (func->num == 2) {
- brcmf_cfg80211_sdio_func(func);
- sd_trace(("F2 found, calling brcmf_sdio_probe...\n"));
- ret = brcmf_sdio_probe(&sdmmc_dev);
+ sdiodev = dev_get_drvdata(&func->card->dev);
+ if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
+ return -ENODEV;
+ sdiodev->func[2] = func;
+
+ brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
+ ret = brcmf_sdio_probe(sdiodev);
}
return ret;
@@ -1068,129 +534,93 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
static void brcmf_ops_sdio_remove(struct sdio_func *func)
{
- sd_trace(("%s Enter\n", __func__));
- sd_info(("func->class=%x\n", func->class));
- sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
- sd_info(("sdio_device: 0x%04x\n", func->device));
- sd_info(("Function#: 0x%04x\n", func->num));
+ struct brcmf_sdio_dev *sdiodev;
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(INFO, "func->class=%x\n", func->class);
+ brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor);
+ brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device);
+ brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
if (func->num == 2) {
- sd_trace(("F2 found, calling brcmf_sdio_remove...\n"));
- brcmf_sdio_remove(&sdmmc_dev);
+ sdiodev = dev_get_drvdata(&func->card->dev);
+ brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
+ brcmf_sdio_remove(sdiodev);
+ dev_set_drvdata(&func->card->dev, NULL);
+ kfree(sdiodev);
}
}
-
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int brcmf_sdio_suspend(struct device *dev)
{
mmc_pm_flag_t sdio_flags;
+ struct brcmf_sdio_dev *sdiodev;
+ struct sdio_func *func = dev_to_sdio_func(dev);
int ret = 0;
- sd_trace(("%s\n", __func__));
+ brcmf_dbg(TRACE, "\n");
+
+ sdiodev = dev_get_drvdata(&func->card->dev);
+
+ atomic_set(&sdiodev->suspend, true);
- sdio_flags = sdio_get_host_pm_caps(gInstance->func[1]);
+ sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]);
if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
- sd_err(("Host can't keep power while suspended\n"));
+ brcmf_dbg(ERROR, "Host can't keep power while suspended\n");
return -EINVAL;
}
- ret = sdio_set_host_pm_flags(gInstance->func[1], MMC_PM_KEEP_POWER);
+ ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER);
if (ret) {
- sd_err(("Failed to set pm_flags\n"));
+ brcmf_dbg(ERROR, "Failed to set pm_flags\n");
return ret;
}
- brcmf_sdio_wdtmr_enable(false);
+ brcmf_sdio_wdtmr_enable(sdiodev, false);
return ret;
}
static int brcmf_sdio_resume(struct device *dev)
{
- brcmf_sdio_wdtmr_enable(true);
- return 0;
-}
-#endif /* CONFIG_PM */
-
-int brcmf_sdioh_osinit(struct sdioh_info *sd)
-{
- struct sdos_info *sdos;
-
- sdos = kmalloc(sizeof(struct sdos_info), GFP_ATOMIC);
- sd->sdos_info = (void *)sdos;
- if (sdos == NULL)
- return -ENOMEM;
+ struct brcmf_sdio_dev *sdiodev;
+ struct sdio_func *func = dev_to_sdio_func(dev);
- sdos->sd = sd;
- spin_lock_init(&sdos->lock);
+ sdiodev = dev_get_drvdata(&func->card->dev);
+ brcmf_sdio_wdtmr_enable(sdiodev, true);
+ atomic_set(&sdiodev->suspend, false);
return 0;
}
-void brcmf_sdioh_osfree(struct sdioh_info *sd)
-{
- struct sdos_info *sdos;
-
- sdos = (struct sdos_info *)sd->sdos_info;
- kfree(sdos);
-}
-
-/* Interrupt enable/disable */
-int brcmf_sdioh_interrupt_set(struct sdioh_info *sd, bool enable)
-{
- unsigned long flags;
- struct sdos_info *sdos;
-
- sd_trace(("%s: %s\n", __func__, enable ? "Enabling" : "Disabling"));
-
- sdos = (struct sdos_info *)sd->sdos_info;
-
- if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
- sd_err(("%s: no handler registered, will not enable\n",
- __func__));
- return -EINVAL;
- }
-
- /* Ensure atomicity for enable/disable calls */
- spin_lock_irqsave(&sdos->lock, flags);
-
- sd->client_intr_enabled = enable;
- if (enable)
- brcmf_sdioh_dev_intr_on(sd);
- else
- brcmf_sdioh_dev_intr_off(sd);
-
- spin_unlock_irqrestore(&sdos->lock, flags);
+static const struct dev_pm_ops brcmf_sdio_pm_ops = {
+ .suspend = brcmf_sdio_suspend,
+ .resume = brcmf_sdio_resume,
+};
+#endif /* CONFIG_PM_SLEEP */
- return 0;
-}
+static struct sdio_driver brcmf_sdmmc_driver = {
+ .probe = brcmf_ops_sdio_probe,
+ .remove = brcmf_ops_sdio_remove,
+ .name = "brcmfmac",
+ .id_table = brcmf_sdmmc_ids,
+#ifdef CONFIG_PM_SLEEP
+ .drv = {
+ .pm = &brcmf_sdio_pm_ops,
+ },
+#endif /* CONFIG_PM_SLEEP */
+};
-/*
- * module init
-*/
-int brcmf_sdio_function_init(void)
+/* bus register interface */
+int brcmf_bus_register(void)
{
- int error = 0;
- sd_trace(("brcmf_sdio_function_init: %s Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- gInstance = kzalloc(sizeof(struct brcmf_sdmmc_instance), GFP_KERNEL);
- if (!gInstance)
- return -ENOMEM;
-
- memset(&sdmmc_dev, 0, sizeof(sdmmc_dev));
- error = sdio_register_driver(&brcmf_sdmmc_driver);
-
- return error;
+ return sdio_register_driver(&brcmf_sdmmc_driver);
}
-/*
- * module cleanup
-*/
-void brcmf_sdio_function_cleanup(void)
+void brcmf_bus_unregister(void)
{
- sd_trace(("%s Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
sdio_unregister_driver(&brcmf_sdmmc_driver);
-
- kfree(gInstance);
}
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd.h b/drivers/staging/brcm80211/brcmfmac/dhd.h
index 82bf04df16d0..4645766b4070 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd.h
@@ -23,10 +23,9 @@
#define BRCMF_VERSION_STR "4.218.248.5"
-#define BRCMF_C_IOCTL_SMLEN 256 /* "small" ioctl buffer required */
-#define BRCMF_C_IOCTL_MEDLEN 1536 /* "med" ioctl buffer required */
-#define BRCMF_C_IOCTL_MAXLEN 8192
-
+/*******************************************************************************
+ * IO codes that are interpreted by dongle firmware
+ ******************************************************************************/
#define BRCMF_C_UP 2
#define BRCMF_C_SET_PROMISC 10
#define BRCMF_C_GET_RATE 12
@@ -83,18 +82,11 @@
#define WLC_PHY_TYPE_LCN 8
#define WLC_PHY_TYPE_NULL 0xf
-#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter, u)
-#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \
- offsetof(struct brcmf_pkt_filter_pattern, mask_and_pattern)
-
#define BRCMF_EVENTING_MASK_LEN 16
#define TOE_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002
-/* maximum channels returned by the get valid channels iovar */
-#define WL_NUMCHANNELS 64
-
#define BRCMF_BSS_INFO_VERSION 108 /* current ver of brcmf_bss_info struct */
/* size of brcmf_scan_params not including variable length array */
@@ -117,11 +109,16 @@
#define BRCMF_SCAN_RESULTS_ABORTED 3
#define BRCMF_SCAN_RESULTS_NO_MEM 4
-#define WL_SOFT_KEY (1 << 0) /* Indicates this key is using soft encrypt */
-#define BRCMF_PRIMARY_KEY (1 << 1) /* primary (ie tx) key */
-#define WL_KF_RES_4 (1 << 4) /* Reserved for backward compat */
-#define WL_KF_RES_5 (1 << 5) /* Reserved for backward compat */
-#define WL_IBSS_PEER_GROUP_KEY (1 << 6) /* Indicates a group key for a IBSS PEER */
+/* Indicates this key is using soft encrypt */
+#define WL_SOFT_KEY (1 << 0)
+/* primary (ie tx) key */
+#define BRCMF_PRIMARY_KEY (1 << 1)
+/* Reserved for backward compat */
+#define WL_KF_RES_4 (1 << 4)
+/* Reserved for backward compat */
+#define WL_KF_RES_5 (1 << 5)
+/* Indicates a group key for a IBSS PEER */
+#define WL_IBSS_PEER_GROUP_KEY (1 << 6)
/* For supporting multiple interfaces */
#define BRCMF_MAX_IFS 16
@@ -136,13 +133,13 @@
#define BRCMF_EVENT_MSG_GROUP 0x04
struct brcmf_event_msg {
- u16 version;
- u16 flags;
- u32 event_type;
- u32 status;
- u32 reason;
- u32 auth_type;
- u32 datalen;
+ __be16 version;
+ __be16 flags;
+ __be32 event_type;
+ __be32 status;
+ __be32 reason;
+ __be32 auth_type;
+ __be32 datalen;
u8 addr[ETH_ALEN];
char ifname[IFNAMSIZ];
} __packed;
@@ -173,6 +170,7 @@ struct dngl_stats {
unsigned long multicast; /* multicast packets received */
};
+/* event codes sent by the dongle to this driver */
#define BRCMF_E_SET_SSID 0
#define BRCMF_E_JOIN 1
#define BRCMF_E_START 2
@@ -332,30 +330,35 @@ enum brcmf_bus_state {
* start matching, the pattern to match, the size of the pattern, and a bitmask
* that indicates which bits within the pattern should be matched.
*/
-struct brcmf_pkt_filter_pattern {
- u32 offset; /* Offset within received packet to start pattern matching.
- * Offset '0' is the first byte of the ethernet header.
- */
- u32 size_bytes; /* Size of the pattern. Bitmask must be the same size. */
- u8 mask_and_pattern[1]; /* Variable length mask and pattern data. mask starts
- * at offset 0. Pattern immediately follows mask.
- */
+struct brcmf_pkt_filter_pattern_le {
+ /*
+ * Offset within received packet to start pattern matching.
+ * Offset '0' is the first byte of the ethernet header.
+ */
+ __le32 offset;
+ /* Size of the pattern. Bitmask must be the same size.*/
+ __le32 size_bytes;
+ /*
+ * Variable length mask and pattern data. mask starts at offset 0.
+ * Pattern immediately follows mask.
+ */
+ u8 mask_and_pattern[1];
};
/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */
-struct brcmf_pkt_filter {
- u32 id; /* Unique filter id, specified by app. */
- u32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
- u32 negate_match; /* Negate the result of filter matches */
+struct brcmf_pkt_filter_le {
+ __le32 id; /* Unique filter id, specified by app. */
+ __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */
+ __le32 negate_match; /* Negate the result of filter matches */
union { /* Filter definitions */
- struct brcmf_pkt_filter_pattern pattern; /* Filter pattern */
+ struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */
} u;
};
/* IOVAR "pkt_filter_enable" parameter. */
-struct brcmf_pkt_filter_enable {
- u32 id; /* Unique filter id */
- u32 enable; /* Enable/disable bool */
+struct brcmf_pkt_filter_enable_le {
+ __le32 id; /* Unique filter id */
+ __le32 enable; /* Enable/disable bool */
};
/* BSS info structure
@@ -363,63 +366,76 @@ struct brcmf_pkt_filter_enable {
* next bss_info structure in a vector (in struct brcmf_scan_results)
*/
struct brcmf_bss_info {
- u32 version; /* version field */
- u32 length; /* byte length of data in this record,
+ __le32 version; /* version field */
+ __le32 length; /* byte length of data in this record,
* starting at version and including IEs
*/
u8 BSSID[ETH_ALEN];
- u16 beacon_period; /* units are Kusec */
- u16 capability; /* Capability information */
+ __le16 beacon_period; /* units are Kusec */
+ __le16 capability; /* Capability information */
u8 SSID_len;
u8 SSID[32];
struct {
- uint count; /* # rates in this set */
- u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
+ __le32 count; /* # rates in this set */
+ u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */
} rateset; /* supported rates */
- chanspec_t chanspec; /* chanspec for bss */
- u16 atim_window; /* units are Kusec */
+ __le16 chanspec; /* chanspec for bss */
+ __le16 atim_window; /* units are Kusec */
u8 dtim_period; /* DTIM period */
- s16 RSSI; /* receive signal strength (in dBm) */
+ __le16 RSSI; /* receive signal strength (in dBm) */
s8 phy_noise; /* noise (in dBm) */
u8 n_cap; /* BSS is 802.11N Capable */
- u32 nbss_cap; /* 802.11N BSS Capabilities (based on HT_CAP_*) */
+ /* 802.11N BSS Capabilities (based on HT_CAP_*): */
+ __le32 nbss_cap;
u8 ctl_ch; /* 802.11N BSS control channel number */
- u32 reserved32[1]; /* Reserved for expansion of BSS properties */
+ __le32 reserved32[1]; /* Reserved for expansion of BSS properties */
u8 flags; /* flags */
u8 reserved[3]; /* Reserved for expansion of BSS properties */
u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
- u16 ie_offset; /* offset at which IEs start, from beginning */
- u32 ie_length; /* byte length of Information Elements */
- s16 SNR; /* average SNR of during frame reception */
+ __le16 ie_offset; /* offset at which IEs start, from beginning */
+ __le32 ie_length; /* byte length of Information Elements */
+ __le16 SNR; /* average SNR of during frame reception */
/* Add new fields here */
/* variable length Information Elements */
};
+struct brcm_rateset_le {
+ /* # rates in this set */
+ __le32 count;
+ /* rates in 500kbps units w/hi bit set if basic */
+ u8 rates[WL_NUMRATES];
+};
+
struct brcmf_ssid {
u32 SSID_len;
unsigned char SSID[32];
};
-struct brcmf_scan_params {
- struct brcmf_ssid ssid; /* default: {0, ""} */
+struct brcmf_ssid_le {
+ __le32 SSID_len;
+ unsigned char SSID[32];
+};
+
+struct brcmf_scan_params_le {
+ struct brcmf_ssid_le ssid_le; /* default: {0, ""} */
u8 bssid[ETH_ALEN]; /* default: bcast */
s8 bss_type; /* default: any,
* DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT
*/
u8 scan_type; /* flags, 0 use default */
- s32 nprobes; /* -1 use default, number of probes per channel */
- s32 active_time; /* -1 use default, dwell time per channel for
+ __le32 nprobes; /* -1 use default, number of probes per channel */
+ __le32 active_time; /* -1 use default, dwell time per channel for
* active scanning
*/
- s32 passive_time; /* -1 use default, dwell time per channel
+ __le32 passive_time; /* -1 use default, dwell time per channel
* for passive scanning
*/
- s32 home_time; /* -1 use default, dwell time for the home channel
- * between channel scans
+ __le32 home_time; /* -1 use default, dwell time for the
+ * home channel between channel scans
*/
- s32 channel_num; /* count of channels and ssids that follow
+ __le32 channel_num; /* count of channels and ssids that follow
*
* low half is count of channels in
* channel_list, 0 means default (use all
@@ -435,22 +451,17 @@ struct brcmf_scan_params {
* fixed parameter portion is assumed, otherwise
* ssid in the fixed portion is ignored
*/
- u16 channel_list[1]; /* list of chanspecs */
+ __le16 channel_list[1]; /* list of chanspecs */
};
/* incremental scan struct */
-struct brcmf_iscan_params {
- u32 version;
- u16 action;
- u16 scan_duration;
- struct brcmf_scan_params params;
+struct brcmf_iscan_params_le {
+ __le32 version;
+ __le16 action;
+ __le16 scan_duration;
+ struct brcmf_scan_params_le params_le;
};
-/* 3 fields + size of brcmf_scan_params, not including variable length array */
-#define BRCMF_ISCAN_PARAMS_FIXED_SIZE \
- (offsetof(struct brcmf_iscan_params, params) + \
- sizeof(struct brcmf_ssid))
-
struct brcmf_scan_results {
u32 buflen;
u32 version;
@@ -458,21 +469,28 @@ struct brcmf_scan_results {
struct brcmf_bss_info bss_info[1];
};
+struct brcmf_scan_results_le {
+ __le32 buflen;
+ __le32 version;
+ __le32 count;
+ struct brcmf_bss_info bss_info[1];
+};
+
/* used for association with a specific BSSID and chanspec list */
-struct brcmf_assoc_params {
- u8 bssid[ETH_ALEN]; /* 00:00:00:00:00:00: broadcast scan */
- s32 chanspec_num; /* 0: all available channels,
- * otherwise count of chanspecs in chanspec_list
- */
- chanspec_t chanspec_list[1]; /* list of chanspecs */
+struct brcmf_assoc_params_le {
+ /* 00:00:00:00:00:00: broadcast scan */
+ u8 bssid[ETH_ALEN];
+ /* 0: all available channels, otherwise count of chanspecs in
+ * chanspec_list */
+ __le32 chanspec_num;
+ /* list of chanspecs */
+ __le16 chanspec_list[1];
};
-#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
- (sizeof(struct brcmf_assoc_params) - sizeof(chanspec_t))
/* used for join with or without a specific bssid and channel list */
struct brcmf_join_params {
- struct brcmf_ssid ssid;
- struct brcmf_assoc_params params;
+ struct brcmf_ssid_le ssid_le;
+ struct brcmf_assoc_params_le params_le;
};
/* size of brcmf_scan_results not including variable length array */
@@ -481,8 +499,14 @@ struct brcmf_join_params {
/* incremental scan results struct */
struct brcmf_iscan_results {
- u32 status;
- struct brcmf_scan_results results;
+ union {
+ u32 status;
+ __le32 status_le;
+ };
+ union {
+ struct brcmf_scan_results results;
+ struct brcmf_scan_results_le results_le;
+ };
};
/* size of brcmf_iscan_results not including variable length array */
@@ -495,40 +519,61 @@ struct brcmf_wsec_key {
u32 len; /* key length */
u8 data[WLAN_MAX_KEY_LEN]; /* key data */
u32 pad_1[18];
- u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
- u32 flags; /* misc flags */
- u32 pad_2[2];
- int pad_3;
- int iv_initialized; /* has IV been initialized already? */
- int pad_4;
+ u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+ u32 flags; /* misc flags */
+ u32 pad_2[3];
+ u32 iv_initialized; /* has IV been initialized already? */
+ u32 pad_3;
/* Rx IV */
struct {
u32 hi; /* upper 32 bits of IV */
u16 lo; /* lower 16 bits of IV */
} rxiv;
- u32 pad_5[2];
+ u32 pad_4[2];
+ u8 ea[ETH_ALEN]; /* per station */
+};
+
+/*
+ * dongle requires same struct as above but with fields in little endian order
+ */
+struct brcmf_wsec_key_le {
+ __le32 index; /* key index */
+ __le32 len; /* key length */
+ u8 data[WLAN_MAX_KEY_LEN]; /* key data */
+ __le32 pad_1[18];
+ __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
+ __le32 flags; /* misc flags */
+ __le32 pad_2[3];
+ __le32 iv_initialized; /* has IV been initialized already? */
+ __le32 pad_3;
+ /* Rx IV */
+ struct {
+ __le32 hi; /* upper 32 bits of IV */
+ __le16 lo; /* lower 16 bits of IV */
+ } rxiv;
+ __le32 pad_4[2];
u8 ea[ETH_ALEN]; /* per station */
};
/* Used to get specific STA parameters */
-struct brcmf_scb_val {
- u32 val;
+struct brcmf_scb_val_le {
+ __le32 val;
u8 ea[ETH_ALEN];
};
/* channel encoding */
-struct brcmf_channel_info {
- int hw_channel;
- int target_channel;
- int scan_channel;
+struct brcmf_channel_info_le {
+ __le32 hw_channel;
+ __le32 target_channel;
+ __le32 scan_channel;
};
-/* Linux network driver ioctl encoding */
-struct brcmf_ioctl {
- uint cmd; /* common ioctl definition */
+/* Bus independent dongle command */
+struct brcmf_dcmd {
+ uint cmd; /* common dongle cmd definition */
void *buf; /* pointer to user buffer */
uint len; /* length of user buffer */
- u8 set; /* get or set request (optional) */
+ u8 set; /* get or set request (optional) */
uint used; /* bytes read or written (optional) */
uint needed; /* bytes needed (optional) */
};
@@ -537,6 +582,7 @@ struct brcmf_ioctl {
struct brcmf_bus; /* device bus info */
struct brcmf_proto; /* device communication protocol info */
struct brcmf_info; /* device driver info */
+struct brcmf_cfg80211_dev; /* cfg80211 device info */
/* Common structure for module and instance linkage */
struct brcmf_pub {
@@ -544,11 +590,11 @@ struct brcmf_pub {
struct brcmf_bus *bus;
struct brcmf_proto *prot;
struct brcmf_info *info;
+ struct brcmf_cfg80211_dev *config;
/* Internal brcmf items */
bool up; /* Driver up/down (to OS) */
bool txoff; /* Transmit flow-controlled */
- bool dongle_reset; /* true = DEVRESET put dongle into reset */
enum brcmf_bus_state busstate;
uint hdrlen; /* Total BRCMF header length (proto + bus) */
uint maxctl; /* Max size rxctl request from proto to bus */
@@ -558,32 +604,45 @@ struct brcmf_pub {
/* Dongle media info */
bool iswl; /* Dongle-resident driver is wl */
unsigned long drv_version; /* Version of dongle-resident driver */
- u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
+ u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */
struct dngl_stats dstats; /* Stats for dongle-based data */
/* Additional stats for the bus level */
- unsigned long tx_packets; /* Data packets sent to dongle */
- unsigned long tx_multicast; /* Multicast data packets sent to dongle */
- unsigned long tx_errors; /* Errors in sending data to dongle */
- unsigned long tx_ctlpkts; /* Control packets sent to dongle */
- unsigned long tx_ctlerrs; /* Errors sending control frames to dongle */
- unsigned long rx_packets; /* Packets sent up the network interface */
- unsigned long rx_multicast; /* Multicast packets sent up the network
- interface */
- unsigned long rx_errors; /* Errors processing rx data packets */
- unsigned long rx_ctlpkts; /* Control frames processed from dongle */
- unsigned long rx_ctlerrs; /* Errors in processing rx control frames */
- unsigned long rx_dropped; /* Packets dropped locally (no memory) */
- unsigned long rx_flushed; /* Packets flushed due to
- unscheduled sendup thread */
- unsigned long wd_dpc_sched; /* Number of times dpc scheduled by
- watchdog timer */
-
- unsigned long rx_readahead_cnt; /* Number of packets where header read-ahead
- was used. */
- unsigned long tx_realloc; /* Number of tx packets we had to realloc for
- headroom */
- unsigned long fc_packets; /* Number of flow control pkts recvd */
+
+ /* Data packets sent to dongle */
+ unsigned long tx_packets;
+ /* Multicast data packets sent to dongle */
+ unsigned long tx_multicast;
+ /* Errors in sending data to dongle */
+ unsigned long tx_errors;
+ /* Control packets sent to dongle */
+ unsigned long tx_ctlpkts;
+ /* Errors sending control frames to dongle */
+ unsigned long tx_ctlerrs;
+ /* Packets sent up the network interface */
+ unsigned long rx_packets;
+ /* Multicast packets sent up the network interface */
+ unsigned long rx_multicast;
+ /* Errors processing rx data packets */
+ unsigned long rx_errors;
+ /* Control frames processed from dongle */
+ unsigned long rx_ctlpkts;
+
+ /* Errors in processing rx control frames */
+ unsigned long rx_ctlerrs;
+ /* Packets dropped locally (no memory) */
+ unsigned long rx_dropped;
+ /* Packets flushed due to unscheduled sendup thread */
+ unsigned long rx_flushed;
+ /* Number of times dpc scheduled by watchdog timer */
+ unsigned long wd_dpc_sched;
+
+ /* Number of packets where header read-ahead was used. */
+ unsigned long rx_readahead_cnt;
+ /* Number of tx packets we had to realloc for headroom */
+ unsigned long tx_realloc;
+ /* Number of flow control pkts recvd */
+ unsigned long fc_packets;
/* Last error return */
int bcmerror;
@@ -614,146 +673,15 @@ struct brcmf_if_event {
u8 bssidx;
};
-struct brcmf_timeout {
- u32 limit; /* Expiration time (usec) */
- u32 increment; /* Current expiration increment (usec) */
- u32 elapsed; /* Current elapsed time (usec) */
- u32 tick; /* O/S tick time (usec) */
-};
-
struct bcmevent_name {
uint event;
const char *name;
};
-#if defined(CONFIG_PM_SLEEP)
-extern atomic_t brcmf_mmc_suspend;
-#define BRCMF_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
-#define _BRCMF_PM_RESUME_WAIT(a, b) do { \
- int retry = 0; \
- while (atomic_read(&brcmf_mmc_suspend) && retry++ != b) { \
- wait_event_timeout(a, false, HZ/100); \
- } \
- } while (0)
-#define BRCMF_PM_RESUME_WAIT(a) _BRCMF_PM_RESUME_WAIT(a, 30)
-#define BRCMF_PM_RESUME_RETURN_ERROR(a) \
- do { if (atomic_read(&brcmf_mmc_suspend)) return a; } while (0)
-
-#define BRCMF_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
-#define BRCMF_SPINWAIT_SLEEP(a, exp, us) do { \
- uint countdown = (us) + 9999; \
- while ((exp) && (countdown >= 10000)) { \
- wait_event_timeout(a, false, HZ/100); \
- countdown -= 10000; \
- } \
- } while (0)
-
-#else
-
-#define BRCMF_PM_RESUME_WAIT_INIT(a)
-#define BRCMF_PM_RESUME_WAIT(a)
-#define BRCMF_PM_RESUME_RETURN_ERROR(a)
-
-#define BRCMF_SPINWAIT_SLEEP_INIT(a)
-#define BRCMF_SPINWAIT_SLEEP(a, exp, us) do { \
- uint countdown = (us) + 9; \
- while ((exp) && (countdown >= 10)) { \
- udelay(10); \
- countdown -= 10; \
- } \
- } while (0)
-
-#endif /* defined(CONFIG_PM_SLEEP) */
-
-/*
- * Insmod parameters for debug/test
- */
-
-/* Use interrupts */
-extern uint brcmf_intr;
-
-/* Use polling */
-extern uint brcmf_poll;
-
-/* ARP offload agent mode */
-extern uint brcmf_arp_mode;
-
-/* ARP offload enable */
-extern uint brcmf_arp_enable;
-
-/* Pkt filte enable control */
-extern uint brcmf_pkt_filter_enable;
-
-/* Pkt filter init setup */
-extern uint brcmf_pkt_filter_init;
-
-/* Pkt filter mode control */
-extern uint brcmf_master_mode;
-
-/* Roaming mode control */
-extern uint brcmf_roam;
-
-/* Roaming mode control */
-extern uint brcmf_radio_up;
-
-/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */
-extern int brcmf_idletime;
-#define BRCMF_IDLETIME_TICKS 1
-
-/* SDIO Drive Strength */
-extern uint brcmf_sdiod_drive_strength;
-
-/* Override to force tx queueing all the time */
-extern uint brcmf_force_tx_queueing;
-
-#ifdef SDTEST
-/* Echo packet generator (SDIO), pkts/s */
-extern uint brcmf_pktgen;
-
-/* Echo packet len (0 => sawtooth, max 1800) */
-extern uint brcmf_pktgen_len;
-#define BRCMF_MAX_PKTGEN_LEN 1800
-#endif
-
extern const struct bcmevent_name bcmevent_names[];
-extern const int bcmevent_names_size;
-
-
-static inline void MUTEX_LOCK_INIT(struct brcmf_pub *drvr)
-{
-}
-
-static inline void MUTEX_LOCK(struct brcmf_pub *drvr)
-{
-}
-
-static inline void MUTEX_UNLOCK(struct brcmf_pub *drvr)
-{
-}
-
-static inline void MUTEX_LOCK_SOFTAP_SET_INIT(struct brcmf_pub *drvr)
-{
-}
-
-static inline void MUTEX_LOCK_SOFTAP_SET(struct brcmf_pub *drvr)
-{
-}
-
-static inline void MUTEX_UNLOCK_SOFTAP_SET(struct brcmf_pub *drvr)
-{
-}
-static inline void MUTEX_LOCK_WL_SCAN_SET_INIT(void)
-{
-}
-
-static inline void MUTEX_LOCK_WL_SCAN_SET(void)
-{
-}
-
-static inline void MUTEX_UNLOCK_WL_SCAN_SET(void)
-{
-}
+extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
+ char *buf, uint len);
/* Indication from bus module regarding presence/insertion of dongle.
* Return struct brcmf_pub pointer, used as handle to OS module in later calls.
@@ -763,7 +691,9 @@ static inline void MUTEX_UNLOCK_WL_SCAN_SET(void)
extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus,
uint bus_hdrlen);
extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx);
-extern int brcmf_netdev_wait_pend8021x(struct net_device *dev);
+extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
+
+extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len);
/* Indication from bus module regarding removal/absence of dongle */
extern void brcmf_detach(struct brcmf_pub *drvr);
@@ -785,25 +715,17 @@ extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
extern void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp,
bool success);
-/* Query ioctl */
-extern int brcmf_proto_cdc_query_ioctl(struct brcmf_pub *drvr, int ifidx,
+/* Query dongle */
+extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
uint cmd, void *buf, uint len);
/* OS independent layer functions */
extern int brcmf_os_proto_block(struct brcmf_pub *drvr);
extern int brcmf_os_proto_unblock(struct brcmf_pub *drvr);
-extern int brcmf_os_ioctl_resp_wait(struct brcmf_pub *drvr, uint *condition,
- bool *pending);
-extern int brcmf_os_ioctl_resp_wake(struct brcmf_pub *drvr);
-extern unsigned int brcmf_os_get_ioctl_resp_timeout(void);
-extern void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
#ifdef BCMDBG
-extern int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size);
+extern int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size);
#endif /* BCMDBG */
-extern void brcmf_timeout_start(struct brcmf_timeout *tmo, uint usec);
-extern int brcmf_timeout_expired(struct brcmf_timeout *tmo);
-
extern int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name);
extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
void *pktdata, struct brcmf_event_msg *,
@@ -811,44 +733,24 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
extern void brcmf_c_init(void);
-extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, void *handle,
- char *name, u8 *mac_addr, u32 flags, u8 bssidx);
+extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
+ struct net_device *ndev, char *name, u8 *mac_addr,
+ u32 flags, u8 bssidx);
extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);
/* Send packet to dongle via data channel */
extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\
struct sk_buff *pkt);
-extern int brcmf_bus_devreset(struct brcmf_pub *drvr, u8 flag);
extern int brcmf_bus_start(struct brcmf_pub *drvr);
extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg);
extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg,
int enable, int master_mode);
-/* Linux network driver ioctl encoding */
-struct brcmf_c_ioctl {
- uint cmd; /* common ioctl definition */
- void *buf; /* pointer to user buffer */
- uint len; /* length of user buffer */
- bool set; /* get or set request (optional) */
- uint used; /* bytes read or written (optional) */
- uint needed; /* bytes needed (optional) */
- uint driver; /* to identify target driver */
-};
-
-/* per-driver magic numbers */
-#define BRCMF_IOCTL_MAGIC 0x00444944
-
-/* bump this number if you change the ioctl interface */
-#define BRCMF_IOCTL_VERSION 1
-#define BRCMF_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */
-
-/* common ioctl definitions */
-#define BRCMF_GET_MAGIC 0
-#define BRCMF_GET_VERSION 1
-#define BRCMF_GET_VAR 2
-#define BRCMF_SET_VAR 3
+#define BRCMF_DCMD_SMLEN 256 /* "small" cmd buffer required */
+#define BRCMF_DCMD_MEDLEN 1536 /* "med" cmd buffer required */
+#define BRCMF_DCMD_MAXLEN 8192 /* max length cmd buffer required */
/* message levels */
#define BRCMF_ERROR_VAL 0x0001
@@ -865,40 +767,10 @@ struct brcmf_c_ioctl {
#define BRCMF_BTA_VAL 0x1000
#define BRCMF_ISCAN_VAL 0x2000
-#ifdef SDTEST
-/* For pktgen iovar */
-struct brcmf_pktgen {
- uint version; /* To allow structure change tracking */
- uint freq; /* Max ticks between tx/rx attempts */
- uint count; /* Test packets to send/rcv each attempt */
- uint print; /* Print counts every <print> attempts */
- uint total; /* Total packets (or bursts) */
- uint minlen; /* Minimum length of packets to send */
- uint maxlen; /* Maximum length of packets to send */
- uint numsent; /* Count of test packets sent */
- uint numrcvd; /* Count of test packets received */
- uint numfail; /* Count of test send failures */
- uint mode; /* Test mode (type of test packets) */
- uint stop; /* Stop after this many tx failures */
-};
-
-/* Version in case structure changes */
-#define BRCMF_PKTGEN_VERSION 2
-
-/* Type of test packets to use */
-#define BRCMF_PKTGEN_ECHO 1 /* Send echo requests */
-#define BRCMF_PKTGEN_SEND 2 /* Send discard packets */
-#define BRCMF_PKTGEN_RXBURST 3 /* Request dongle send N packets */
-#define BRCMF_PKTGEN_RECV 4 /* Continuous rx from continuous
- tx dongle */
-#endif /* SDTEST */
-
/* Enter idle immediately (no timeout) */
#define BRCMF_IDLE_IMMEDIATE (-1)
-
-/* Values for idleclock iovar: other values are the sd_divisor to use
- when idle */
#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change
when idle */
+#define BRCMF_IDLE_INTERVAL 1
#endif /* _BRCMF_H_ */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
index 653cf0daa0eb..a249407c9a1b 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_bus.h
@@ -18,36 +18,27 @@
#define _BRCMF_BUS_H_
/* Packet alignment for most efficient SDIO (can change based on platform) */
-#ifndef BRCMF_SDALIGN
-#define BRCMF_SDALIGN 32
-#endif
-#if !ISPOWEROF2(BRCMF_SDALIGN)
-#error BRCMF_SDALIGN is not a power of 2!
-#endif
+#define BRCMF_SDALIGN (1 << 6)
+
+/* watchdog polling interval in ms */
+#define BRCMF_WD_POLL_MS 10
/*
* Exported from brcmf bus module (brcmf_usb, brcmf_sdio)
*/
-/* dongle ram module parameter */
-extern int brcmf_dongle_memsize;
-
-/* Tx/Rx bounds module parameters */
-extern uint brcmf_txbound;
-extern uint brcmf_rxbound;
-
-/* Watchdog timer interval */
-extern uint brcmf_watchdog_ms;
-
/* Indicate (dis)interest in finding dongles. */
extern int brcmf_bus_register(void);
extern void brcmf_bus_unregister(void);
+/* obtain linux device object providing bus function */
+extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus);
+
/* Stop bus module: clear pending frames, disable data flow */
-extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus, bool enforce_mutex);
+extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus);
/* Initialize bus module: prepare for communication w/dongle */
-extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr, bool enforce_mutex);
+extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr);
/* Send a data frame to the dongle. Callee disposes of txp. */
extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp);
@@ -61,18 +52,6 @@ brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen);
extern int
brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen);
-/* Check for and handle local prot-specific iovar commands */
-extern int brcmf_sdbrcm_bus_iovar_op(struct brcmf_pub *drvr, const char *name,
- void *params, int plen, void *arg, int len,
- bool set);
-
-/* Add bus dump output to a buffer */
-extern void brcmf_sdbrcm_bus_dump(struct brcmf_pub *drvr,
- struct brcmu_strbuf *strbuf);
-
-/* Clear any bus counters */
-extern void brcmf_bus_clearcounts(struct brcmf_pub *drvr);
-
extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick);
#endif /* _BRCMF_BUS_H_ */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
index 345acabe935e..e34c5c3d1d55 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
@@ -14,6 +14,11 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/*******************************************************************************
+ * Communicates with the dongle by using dcmd codes.
+ * For certain dcmd codes, the dongle interprets string data from the host.
+ ******************************************************************************/
+
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/sched.h>
@@ -27,29 +32,26 @@
#include "dhd_bus.h"
#include "dhd_dbg.h"
-struct brcmf_proto_cdc_ioctl {
- u32 cmd; /* ioctl command value */
- u32 len; /* lower 16: output buflen;
+struct brcmf_proto_cdc_dcmd {
+ __le32 cmd; /* dongle command value */
+ __le32 len; /* lower 16: output buflen;
* upper 16: input buflen (excludes header) */
- u32 flags; /* flag defns given below */
- u32 status; /* status code returned from the device */
+ __le32 flags; /* flag defns given below */
+ __le32 status; /* status code returned from the device */
};
/* Max valid buffer size that can be sent to the dongle */
#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)
/* CDC flag definitions */
-#define CDCF_IOC_ERROR 0x01 /* 1=ioctl cmd failed */
-#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */
-#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */
-#define CDCF_IOC_IF_SHIFT 12
-#define CDCF_IOC_ID_MASK 0xFFFF0000 /* id an ioctl pairing */
-#define CDCF_IOC_ID_SHIFT 16 /* ID Mask shift bits */
-#define CDC_IOC_ID(flags) \
- (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
-#define CDC_SET_IF_IDX(hdr, idx) \
- ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | \
- ((idx) << CDCF_IOC_IF_SHIFT)))
+#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */
+#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
+#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */
+#define CDC_DCMD_IF_SHIFT 12
+#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
+#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
+#define CDC_DCMD_ID(flags) \
+ (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
/*
* BDC header - Broadcom specific extension of CDC.
@@ -79,7 +81,7 @@ struct brcmf_proto_bdc_header {
};
-#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
+#define RETRIES 2 /* # of retries to retrieve matching dcmd response */
#define BUS_HEADER_LEN (16+BRCMF_SDALIGN) /* Must be atleast SDPCM_RESERVE
* (amount of header tha might be added)
* plus any space that might be needed
@@ -94,17 +96,17 @@ struct brcmf_proto {
u8 pending;
u32 lastcmd;
u8 bus_header[BUS_HEADER_LEN];
- struct brcmf_proto_cdc_ioctl msg;
- unsigned char buf[BRCMF_C_IOCTL_MAXLEN + ROUND_UP_MARGIN];
+ struct brcmf_proto_cdc_dcmd msg;
+ unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];
};
static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)
{
struct brcmf_proto *prot = drvr->prot;
int len = le32_to_cpu(prot->msg.len) +
- sizeof(struct brcmf_proto_cdc_ioctl);
+ sizeof(struct brcmf_proto_cdc_dcmd);
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
@@ -123,31 +125,31 @@ static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
int ret;
struct brcmf_proto *prot = drvr->prot;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
do {
ret = brcmf_sdbrcm_bus_rxctl(drvr->bus,
(unsigned char *)&prot->msg,
- len + sizeof(struct brcmf_proto_cdc_ioctl));
+ len + sizeof(struct brcmf_proto_cdc_dcmd));
if (ret < 0)
break;
- } while (CDC_IOC_ID(le32_to_cpu(prot->msg.flags)) != id);
+ } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id);
return ret;
}
int
-brcmf_proto_cdc_query_ioctl(struct brcmf_pub *drvr, int ifidx, uint cmd,
- void *buf, uint len)
+brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+ void *buf, uint len)
{
struct brcmf_proto *prot = drvr->prot;
- struct brcmf_proto_cdc_ioctl *msg = &prot->msg;
+ struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
void *info;
int ret = 0, retries = 0;
- u32 id, flags = 0;
+ u32 id, flags;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- BRCMF_CTL(("%s: cmd %d len %d\n", __func__, cmd, len));
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
/* Respond "bcmerror" and "bcmerrorstr" with local cache */
if (cmd == BRCMF_C_GET_VAR && buf) {
@@ -161,21 +163,22 @@ brcmf_proto_cdc_query_ioctl(struct brcmf_pub *drvr, int ifidx, uint cmd,
}
}
- memset(msg, 0, sizeof(struct brcmf_proto_cdc_ioctl));
+ memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
- msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
- CDC_SET_IF_IDX(msg, ifidx);
- msg->flags = cpu_to_le32(msg->flags);
+ flags = (++prot->reqid << CDC_DCMD_ID_SHIFT);
+ flags = (flags & ~CDC_DCMD_IF_MASK) |
+ (ifidx << CDC_DCMD_IF_SHIFT);
+ msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(prot->buf, buf, len);
ret = brcmf_proto_cdc_msg(drvr);
if (ret < 0) {
- BRCMF_ERROR(("brcmf_proto_cdc_query_ioctl: brcmf_proto_cdc_msg "
- "failed w/status %d\n", ret));
+ brcmf_dbg(ERROR, "brcmf_proto_cdc_msg failed w/status %d\n",
+ ret);
goto done;
}
@@ -186,14 +189,13 @@ retry:
goto done;
flags = le32_to_cpu(msg->flags);
- id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
+ id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
if ((id < prot->reqid) && (++retries < RETRIES))
goto retry;
if (id != prot->reqid) {
- BRCMF_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
- brcmf_ifname(drvr, ifidx), __func__, id,
- prot->reqid));
+ brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n",
+ brcmf_ifname(drvr, ifidx), id, prot->reqid);
ret = -EINVAL;
goto done;
}
@@ -209,7 +211,7 @@ retry:
}
/* Check the ERROR flag */
- if (flags & CDCF_IOC_ERROR) {
+ if (flags & CDC_DCMD_ERROR) {
ret = le32_to_cpu(msg->status);
/* Cache error from dongle */
drvr->dongle_error = ret;
@@ -219,24 +221,25 @@ done:
return ret;
}
-int brcmf_proto_cdc_set_ioctl(struct brcmf_pub *drvr, int ifidx, uint cmd,
- void *buf, uint len)
+int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
+ void *buf, uint len)
{
struct brcmf_proto *prot = drvr->prot;
- struct brcmf_proto_cdc_ioctl *msg = &prot->msg;
+ struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
int ret = 0;
u32 flags, id;
- BRCMF_TRACE(("%s: Enter\n", __func__));
- BRCMF_CTL(("%s: cmd %d len %d\n", __func__, cmd, len));
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len);
- memset(msg, 0, sizeof(struct brcmf_proto_cdc_ioctl));
+ memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));
msg->cmd = cpu_to_le32(cmd);
msg->len = cpu_to_le32(len);
- msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET;
- CDC_SET_IF_IDX(msg, ifidx);
- msg->flags = cpu_to_le32(msg->flags);
+ flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;
+ flags = (flags & ~CDC_DCMD_IF_MASK) |
+ (ifidx << CDC_DCMD_IF_SHIFT);
+ msg->flags = cpu_to_le32(flags);
if (buf)
memcpy(prot->buf, buf, len);
@@ -250,18 +253,17 @@ int brcmf_proto_cdc_set_ioctl(struct brcmf_pub *drvr, int ifidx, uint cmd,
goto done;
flags = le32_to_cpu(msg->flags);
- id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
+ id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;
if (id != prot->reqid) {
- BRCMF_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
- brcmf_ifname(drvr, ifidx), __func__, id,
- prot->reqid));
+ brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n",
+ brcmf_ifname(drvr, ifidx), id, prot->reqid);
ret = -EINVAL;
goto done;
}
/* Check the ERROR flag */
- if (flags & CDCF_IOC_ERROR) {
+ if (flags & CDC_DCMD_ERROR) {
ret = le32_to_cpu(msg->status);
/* Cache error from dongle */
drvr->dongle_error = ret;
@@ -272,65 +274,64 @@ done:
}
int
-brcmf_proto_ioctl(struct brcmf_pub *drvr, int ifidx, struct brcmf_ioctl *ioc,
- void *buf, int len)
+brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
+ int len)
{
struct brcmf_proto *prot = drvr->prot;
int ret = -1;
if (drvr->busstate == BRCMF_BUS_DOWN) {
- BRCMF_ERROR(("%s : bus is down. we have nothing to do\n",
- __func__));
+ brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
return ret;
}
brcmf_os_proto_block(drvr);
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- if (len > BRCMF_C_IOCTL_MAXLEN)
+ if (len > BRCMF_DCMD_MAXLEN)
goto done;
if (prot->pending == true) {
- BRCMF_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) "
- "lastcmd=0x%x (%lu)\n",
- ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
- (unsigned long)prot->lastcmd));
- if ((ioc->cmd == BRCMF_C_SET_VAR) ||
- (ioc->cmd == BRCMF_C_GET_VAR))
- BRCMF_TRACE(("iovar cmd=%s\n", (char *)buf));
+ brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
+ dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd,
+ (unsigned long)prot->lastcmd);
+ if (dcmd->cmd == BRCMF_C_SET_VAR ||
+ dcmd->cmd == BRCMF_C_GET_VAR)
+ brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf);
goto done;
}
prot->pending = true;
- prot->lastcmd = ioc->cmd;
- if (ioc->set)
- ret = brcmf_proto_cdc_set_ioctl(drvr, ifidx, ioc->cmd,
- buf, len);
+ prot->lastcmd = dcmd->cmd;
+ if (dcmd->set)
+ ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd,
+ dcmd->buf, len);
else {
- ret = brcmf_proto_cdc_query_ioctl(drvr, ifidx, ioc->cmd,
- buf, len);
+ ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd,
+ dcmd->buf, len);
if (ret > 0)
- ioc->used = ret - sizeof(struct brcmf_proto_cdc_ioctl);
+ dcmd->used = ret -
+ sizeof(struct brcmf_proto_cdc_dcmd);
}
- /* Too many programs assume ioctl() returns 0 on success */
if (ret >= 0)
ret = 0;
else {
- struct brcmf_proto_cdc_ioctl *msg = &prot->msg;
+ struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
/* len == needed when set/query fails from dongle */
- ioc->needed = le32_to_cpu(msg->len);
+ dcmd->needed = le32_to_cpu(msg->len);
}
- /* Intercept the wme_dp ioctl here */
- if (!ret && ioc->cmd == BRCMF_C_SET_VAR &&
- !strcmp(buf, "wme_dp")) {
- int slen, val = 0;
+ /* Intercept the wme_dp dongle cmd here */
+ if (!ret && dcmd->cmd == BRCMF_C_SET_VAR &&
+ !strcmp(dcmd->buf, "wme_dp")) {
+ int slen;
+ __le32 val = 0;
slen = strlen("wme_dp") + 1;
if (len >= (int)(slen + sizeof(int)))
- memcpy(&val, (char *)buf + slen, sizeof(int));
+ memcpy(&val, (char *)dcmd->buf + slen, sizeof(int));
drvr->wme_dp = (u8) le32_to_cpu(val);
}
@@ -342,15 +343,14 @@ done:
return ret;
}
-#define PKTSUMNEEDED(skb) \
- (((struct sk_buff *)(skb))->ip_summed == CHECKSUM_PARTIAL)
-#define PKTSETSUMGOOD(skb, x) \
- (((struct sk_buff *)(skb))->ip_summed = \
- ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE))
+static bool pkt_sum_needed(struct sk_buff *skb)
+{
+ return skb->ip_summed == CHECKSUM_PARTIAL;
+}
-void brcmf_proto_dump(struct brcmf_pub *drvr, struct brcmu_strbuf *strbuf)
+static void pkt_set_sum_good(struct sk_buff *skb, bool x)
{
- brcmu_bprintf(strbuf, "Protocol CDC: reqid %d\n", drvr->prot->reqid);
+ skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);
}
void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
@@ -358,7 +358,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
{
struct brcmf_proto_bdc_header *h;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* Push BDC header used to convey priority for buses that don't */
@@ -367,7 +367,7 @@ void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,
h = (struct brcmf_proto_bdc_header *)(pktbuf->data);
h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
- if (PKTSUMNEEDED(pktbuf))
+ if (pkt_sum_needed(pktbuf))
h->flags |= BDC_FLAG_SUM_NEEDED;
h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);
@@ -381,13 +381,13 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx,
{
struct brcmf_proto_bdc_header *h;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* Pop BDC header used to convey priority for buses that don't */
if (pktbuf->len < BDC_HEADER_LEN) {
- BRCMF_ERROR(("%s: rx data too short (%d < %d)\n", __func__,
- pktbuf->len, BDC_HEADER_LEN));
+ brcmf_dbg(ERROR, "rx data too short (%d < %d)\n",
+ pktbuf->len, BDC_HEADER_LEN);
return -EBADE;
}
@@ -395,23 +395,21 @@ int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx,
*ifidx = BDC_GET_IF_IDX(h);
if (*ifidx >= BRCMF_MAX_IFS) {
- BRCMF_ERROR(("%s: rx data ifnum out of range (%d)\n",
- __func__, *ifidx));
+ brcmf_dbg(ERROR, "rx data ifnum out of range (%d)\n", *ifidx);
return -EBADE;
}
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
BDC_PROTO_VER) {
- BRCMF_ERROR(("%s: non-BDC packet received, flags 0x%x\n",
- brcmf_ifname(drvr, *ifidx), h->flags));
+ brcmf_dbg(ERROR, "%s: non-BDC packet received, flags 0x%x\n",
+ brcmf_ifname(drvr, *ifidx), h->flags);
return -EBADE;
}
if (h->flags & BDC_FLAG_SUM_GOOD) {
- BRCMF_INFO(("%s: BDC packet received with good rx-csum, "
- "flags 0x%x\n",
- brcmf_ifname(drvr, *ifidx), h->flags));
- PKTSETSUMGOOD(pktbuf, true);
+ brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n",
+ brcmf_ifname(drvr, *ifidx), h->flags);
+ pkt_set_sum_good(pktbuf, true);
}
pktbuf->priority = h->priority & BDC_PRIORITY_MASK;
@@ -426,21 +424,19 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
struct brcmf_proto *cdc;
cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC);
- if (!cdc) {
- BRCMF_ERROR(("%s: kmalloc failed\n", __func__));
+ if (!cdc)
goto fail;
- }
/* ensure that the msg buf directly follows the cdc msg struct */
if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) {
- BRCMF_ERROR(("struct brcmf_proto is not correctly defined\n"));
+ brcmf_dbg(ERROR, "struct brcmf_proto is not correctly defined\n");
goto fail;
}
drvr->prot = cdc;
drvr->hdrlen += BDC_HEADER_LEN;
- drvr->maxctl = BRCMF_C_IOCTL_MAXLEN +
- sizeof(struct brcmf_proto_cdc_ioctl) + ROUND_UP_MARGIN;
+ drvr->maxctl = BRCMF_DCMD_MAXLEN +
+ sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;
return 0;
fail:
@@ -472,13 +468,13 @@ int brcmf_proto_init(struct brcmf_pub *drvr)
int ret = 0;
char buf[128];
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
brcmf_os_proto_block(drvr);
/* Get the device MAC address */
strcpy(buf, "cur_etheraddr");
- ret = brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR,
+ ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR,
buf, sizeof(buf));
if (ret < 0) {
brcmf_os_proto_unblock(drvr);
@@ -488,7 +484,7 @@ int brcmf_proto_init(struct brcmf_pub *drvr)
brcmf_os_proto_unblock(drvr);
- ret = brcmf_c_preinit_ioctls(drvr);
+ ret = brcmf_c_preinit_dcmds(drvr);
/* Always assumes wl for now */
drvr->iswl = true;
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_common.c b/drivers/staging/brcm80211/brcmfmac/dhd_common.c
index fdec4683c422..891826197f96 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_common.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_common.c
@@ -30,73 +30,61 @@
#define DOT11_OUI_LEN 3
#define BCMILCP_BCM_SUBTYPE_EVENT 1
#define PKTFILTER_BUF_SIZE 2048
+#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */
int brcmf_msg_level;
#define MSGTRACE_VERSION 1
+#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u)
+#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \
+ offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern)
+
#ifdef BCMDBG
-const char brcmf_version[] =
-"Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " __DATE__
-" at " __TIME__;
+static const char brcmf_version[] =
+ "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
+ __DATE__ " at " __TIME__;
#else
-const char brcmf_version[] = "Dongle Host Driver, version " BRCMF_VERSION_STR;
+static const char brcmf_version[] =
+ "Dongle Host Driver, version " BRCMF_VERSION_STR;
#endif
-/* IOVar table */
-enum {
- IOV_VERSION = 1,
- IOV_MSGLEVEL,
- IOV_BCMERRORSTR,
- IOV_BCMERROR,
- IOV_DUMP,
- IOV_CLEARCOUNTS,
- IOV_LOGDUMP,
- IOV_LOGCAL,
- IOV_LOGSTAMP,
- IOV_GPIOOB,
- IOV_IOCTLTIMEOUT,
- IOV_LAST
-};
-
-const struct brcmu_iovar brcmf_iovars[] = {
- {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(brcmf_version)}
- ,
-#ifdef BCMDBG
- {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0}
- ,
-#endif /* BCMDBG */
- {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN}
- ,
- {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0}
- ,
- {"dump", IOV_DUMP, 0, IOVT_BUFFER, BRCMF_IOCTL_MAXLEN}
- ,
- {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0}
- ,
- {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0}
- ,
- {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0}
- ,
- {NULL, 0, 0, 0, 0}
-};
-
/* Message trace header */
struct msgtrace_hdr {
u8 version;
u8 spare;
- u16 len; /* Len of the trace */
- u32 seqnum; /* Sequence number of message. Useful
+ __be16 len; /* Len of the trace */
+ __be32 seqnum; /* Sequence number of message. Useful
* if the messsage has been lost
* because of DMA error or a bus reset
* (ex: SDIO Func2)
*/
- u32 discarded_bytes; /* Number of discarded bytes because of
+ __be32 discarded_bytes; /* Number of discarded bytes because of
trace overflow */
- u32 discarded_printf; /* Number of discarded printf
+ __be32 discarded_printf; /* Number of discarded printf
because of trace overflow */
} __packed;
+
+uint
+brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
+{
+ uint len;
+
+ len = strlen(name) + 1;
+
+ if ((len + datalen) > buflen)
+ return 0;
+
+ strncpy(buf, name, buflen);
+
+ /* append data onto the end of the name string */
+ memcpy(&buf[len], data, datalen);
+ len += datalen;
+
+ return len;
+}
+
void brcmf_c_init(void)
{
/* Init global variables at run-time, not as part of the declaration.
@@ -110,147 +98,6 @@ void brcmf_c_init(void)
brcmf_msg_level = BRCMF_ERROR_VAL;
}
-static int brcmf_c_dump(struct brcmf_pub *drvr, char *buf, int buflen)
-{
- struct brcmu_strbuf b;
- struct brcmu_strbuf *strbuf = &b;
-
- brcmu_binit(strbuf, buf, buflen);
-
- /* Base info */
- brcmu_bprintf(strbuf, "%s\n", brcmf_version);
- brcmu_bprintf(strbuf, "\n");
- brcmu_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
- drvr->up, drvr->txoff, drvr->busstate);
- brcmu_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
- drvr->hdrlen, drvr->maxctl, drvr->rxsz);
- brcmu_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %pM\n",
- drvr->iswl, drvr->drv_version, &drvr->mac);
- brcmu_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", drvr->bcmerror,
- drvr->tickcnt);
-
- brcmu_bprintf(strbuf, "dongle stats:\n");
- brcmu_bprintf(strbuf,
- "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
- drvr->dstats.tx_packets, drvr->dstats.tx_bytes,
- drvr->dstats.tx_errors, drvr->dstats.tx_dropped);
- brcmu_bprintf(strbuf,
- "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
- drvr->dstats.rx_packets, drvr->dstats.rx_bytes,
- drvr->dstats.rx_errors, drvr->dstats.rx_dropped);
- brcmu_bprintf(strbuf, "multicast %ld\n", drvr->dstats.multicast);
-
- brcmu_bprintf(strbuf, "bus stats:\n");
- brcmu_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
- drvr->tx_packets, drvr->tx_multicast, drvr->tx_errors);
- brcmu_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
- drvr->tx_ctlpkts, drvr->tx_ctlerrs);
- brcmu_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld\n",
- drvr->rx_packets, drvr->rx_multicast, drvr->rx_errors);
- brcmu_bprintf(strbuf,
- "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
- drvr->rx_ctlpkts, drvr->rx_ctlerrs, drvr->rx_dropped,
- drvr->rx_flushed);
- brcmu_bprintf(strbuf,
- "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
- drvr->rx_readahead_cnt, drvr->tx_realloc, drvr->fc_packets);
- brcmu_bprintf(strbuf, "wd_dpc_sched %ld\n", drvr->wd_dpc_sched);
- brcmu_bprintf(strbuf, "\n");
-
- /* Add any prot info */
- brcmf_proto_dump(drvr, strbuf);
- brcmu_bprintf(strbuf, "\n");
-
- /* Add any bus info */
- brcmf_sdbrcm_bus_dump(drvr, strbuf);
-
- return !strbuf->size ? -EOVERFLOW : 0;
-}
-
-static int
-brcmf_c_doiovar(struct brcmf_pub *drvr, const struct brcmu_iovar *vi,
- u32 actionid, const char *name, void *params, int plen,
- void *arg, int len, int val_size)
-{
- int bcmerror = 0;
- s32 int_val = 0;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- bcmerror = brcmu_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid));
- if (bcmerror != 0)
- goto exit;
-
- if (plen >= (int)sizeof(int_val))
- memcpy(&int_val, params, sizeof(int_val));
-
- switch (actionid) {
- case IOV_GVAL(IOV_VERSION):
- /* Need to have checked buffer length */
- strncpy((char *)arg, brcmf_version, len);
- break;
-
- case IOV_GVAL(IOV_MSGLEVEL):
- int_val = (s32) brcmf_msg_level;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_MSGLEVEL):
- brcmf_msg_level = int_val;
- break;
-
- case IOV_GVAL(IOV_BCMERRORSTR):
- strncpy((char *)arg, "bcm_error",
- BCME_STRLEN);
- ((char *)arg)[BCME_STRLEN - 1] = 0x00;
- break;
-
- case IOV_GVAL(IOV_BCMERROR):
- int_val = (s32) drvr->bcmerror;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_GVAL(IOV_DUMP):
- bcmerror = brcmf_c_dump(drvr, arg, len);
- break;
-
- case IOV_SVAL(IOV_CLEARCOUNTS):
- drvr->tx_packets = drvr->rx_packets = 0;
- drvr->tx_errors = drvr->rx_errors = 0;
- drvr->tx_ctlpkts = drvr->rx_ctlpkts = 0;
- drvr->tx_ctlerrs = drvr->rx_ctlerrs = 0;
- drvr->rx_dropped = 0;
- drvr->rx_readahead_cnt = 0;
- drvr->tx_realloc = 0;
- drvr->wd_dpc_sched = 0;
- memset(&drvr->dstats, 0, sizeof(drvr->dstats));
- brcmf_bus_clearcounts(drvr);
- break;
-
- case IOV_GVAL(IOV_IOCTLTIMEOUT):{
- int_val = (s32) brcmf_os_get_ioctl_resp_timeout();
- memcpy(arg, &int_val, sizeof(int_val));
- break;
- }
-
- case IOV_SVAL(IOV_IOCTLTIMEOUT):{
- if (int_val <= 0)
- bcmerror = -EINVAL;
- else
- brcmf_os_set_ioctl_resp_timeout((unsigned int)
- int_val);
- break;
- }
-
- default:
- bcmerror = -ENOTSUPP;
- break;
- }
-
-exit:
- return bcmerror;
-}
-
bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
struct sk_buff *pkt, int prec)
{
@@ -278,159 +125,28 @@ bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q,
/* Evict if needed */
if (eprec >= 0) {
/* Detect queueing to unconfigured precedence */
- discard_oldest = AC_BITMAP_TST(drvr->wme_dp, eprec);
+ discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec);
if (eprec == prec && !discard_oldest)
return false; /* refuse newer (incoming) packet */
/* Evict packet according to discard policy */
p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
brcmu_pktq_pdeq_tail(q, eprec);
- if (p == NULL) {
- BRCMF_ERROR(("%s: brcmu_pktq_penq() failed, oldest %d.",
- __func__, discard_oldest));
- }
+ if (p == NULL)
+ brcmf_dbg(ERROR, "brcmu_pktq_penq() failed, oldest %d\n",
+ discard_oldest);
+
brcmu_pkt_buf_free_skb(p);
}
/* Enqueue */
p = brcmu_pktq_penq(q, prec, pkt);
- if (p == NULL) {
- BRCMF_ERROR(("%s: brcmu_pktq_penq() failed.", __func__));
- }
+ if (p == NULL)
+ brcmf_dbg(ERROR, "brcmu_pktq_penq() failed\n");
return p != NULL;
}
-static int
-brcmf_c_iovar_op(struct brcmf_pub *drvr, const char *name,
- void *params, int plen, void *arg, int len, bool set)
-{
- int bcmerror = 0;
- int val_size;
- const struct brcmu_iovar *vi = NULL;
- u32 actionid;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (name == NULL || len <= 0)
- return -EINVAL;
-
- /* Set does not take qualifiers */
- if (set && (params || plen))
- return -EINVAL;
-
- /* Get must have return space;*/
- if (!set && !(arg && len))
- return -EINVAL;
-
- vi = brcmu_iovar_lookup(brcmf_iovars, name);
- if (vi == NULL) {
- bcmerror = -ENOTSUPP;
- goto exit;
- }
-
- BRCMF_CTL(("%s: %s %s, len %d plen %d\n", __func__,
- name, (set ? "set" : "get"), len, plen));
-
- /* set up 'params' pointer in case this is a set command so that
- * the convenience int and bool code can be common to set and get
- */
- if (params == NULL) {
- params = arg;
- plen = len;
- }
-
- if (vi->type == IOVT_VOID)
- val_size = 0;
- else if (vi->type == IOVT_BUFFER)
- val_size = len;
- else
- /* all other types are integer sized */
- val_size = sizeof(int);
-
- actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
- bcmerror =
- brcmf_c_doiovar(drvr, vi, actionid, name, params, plen, arg, len,
- val_size);
-
-exit:
- return bcmerror;
-}
-
-int brcmf_c_ioctl(struct brcmf_pub *drvr, struct brcmf_c_ioctl *ioc, void *buf,
- uint buflen)
-{
- int bcmerror = 0;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (!buf)
- return -EINVAL;
-
- switch (ioc->cmd) {
- case BRCMF_GET_MAGIC:
- if (buflen < sizeof(int))
- bcmerror = -EOVERFLOW;
- else
- *(int *)buf = BRCMF_IOCTL_MAGIC;
- break;
-
- case BRCMF_GET_VERSION:
- if (buflen < sizeof(int))
- bcmerror = -EOVERFLOW;
- else
- *(int *)buf = BRCMF_IOCTL_VERSION;
- break;
-
- case BRCMF_GET_VAR:
- case BRCMF_SET_VAR:{
- char *arg;
- uint arglen;
-
- /* scan past the name to any arguments */
- for (arg = buf, arglen = buflen; *arg && arglen;
- arg++, arglen--)
- ;
-
- if (*arg) {
- bcmerror = -EOVERFLOW;
- break;
- }
-
- /* account for the NUL terminator */
- arg++, arglen--;
-
- /* call with the appropriate arguments */
- if (ioc->cmd == BRCMF_GET_VAR)
- bcmerror = brcmf_c_iovar_op(drvr, buf, arg,
- arglen, buf, buflen, IOV_GET);
- else
- bcmerror =
- brcmf_c_iovar_op(drvr, buf, NULL, 0, arg,
- arglen, IOV_SET);
- if (bcmerror != -ENOTSUPP)
- break;
-
- /* if still not found, try bus module */
- if (ioc->cmd == BRCMF_GET_VAR)
- bcmerror = brcmf_sdbrcm_bus_iovar_op(drvr,
- buf, arg, arglen, buf, buflen,
- IOV_GET);
- else
- bcmerror = brcmf_sdbrcm_bus_iovar_op(drvr,
- buf, NULL, 0, arg, arglen,
- IOV_SET);
-
- break;
- }
-
- default:
- bcmerror = -ENOTSUPP;
- }
-
- return bcmerror;
-}
-
-#ifdef SHOW_EVENTS
+#ifdef BCMDBG
static void
brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
{
@@ -502,6 +218,11 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
};
uint event_type, flags, auth_type, datalen;
+ static u32 seqnum_prev;
+ struct msgtrace_hdr hdr;
+ u32 nblost;
+ char *s, *p;
+
event_type = be32_to_cpu(event->event_type);
flags = be16_to_cpu(event->flags);
status = be32_to_cpu(event->status);
@@ -517,9 +238,9 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
event_name = event_names[i].event_name;
}
- BRCMF_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type));
- BRCMF_EVENT(("flags 0x%04x, status %d, reason %d, auth_type %d"
- " MAC %s\n", flags, status, reason, auth_type, eabuf));
+ brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type);
+ brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
+ flags, status, reason, auth_type, eabuf);
if (flags & BRCMF_EVENT_MSG_LINK)
link = true;
@@ -532,36 +253,34 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
case BRCMF_E_START:
case BRCMF_E_DEAUTH:
case BRCMF_E_DISASSOC:
- BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
break;
case BRCMF_E_ASSOC_IND:
case BRCMF_E_REASSOC_IND:
- BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
break;
case BRCMF_E_ASSOC:
case BRCMF_E_REASSOC:
- if (status == BRCMF_E_STATUS_SUCCESS) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n",
- event_name, eabuf));
- } else if (status == BRCMF_E_STATUS_TIMEOUT) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n",
- event_name, eabuf));
- } else if (status == BRCMF_E_STATUS_FAIL) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, FAILURE,"
- " reason %d\n", event_name, eabuf,
- (int)reason));
- } else {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, unexpected status "
- "%d\n", event_name, eabuf, (int)status));
- }
+ if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n",
+ event_name, eabuf);
+ else if (status == BRCMF_E_STATUS_TIMEOUT)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n",
+ event_name, eabuf);
+ else if (status == BRCMF_E_STATUS_FAIL)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
+ event_name, eabuf, (int)reason);
+ else
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n",
+ event_name, eabuf, (int)status);
break;
case BRCMF_E_DEAUTH_IND:
case BRCMF_E_DISASSOC_IND:
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name,
- eabuf, (int)reason));
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n",
+ event_name, eabuf, (int)reason);
break;
case BRCMF_E_AUTH:
@@ -574,19 +293,18 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
auth_str = err_msg;
}
- if (event_type == BRCMF_E_AUTH_IND) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name,
- eabuf, auth_str));
- } else if (status == BRCMF_E_STATUS_SUCCESS) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
- event_name, eabuf, auth_str));
- } else if (status == BRCMF_E_STATUS_TIMEOUT) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
- event_name, eabuf, auth_str));
- } else if (status == BRCMF_E_STATUS_FAIL) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, "
- "reason %d\n",
- event_name, eabuf, auth_str, (int)reason));
+ if (event_type == BRCMF_E_AUTH_IND)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n",
+ event_name, eabuf, auth_str);
+ else if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n",
+ event_name, eabuf, auth_str);
+ else if (status == BRCMF_E_STATUS_TIMEOUT)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
+ event_name, eabuf, auth_str);
+ else if (status == BRCMF_E_STATUS_FAIL) {
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
+ event_name, eabuf, auth_str, (int)reason);
}
break;
@@ -594,149 +312,138 @@ brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
case BRCMF_E_JOIN:
case BRCMF_E_ROAM:
case BRCMF_E_SET_SSID:
- if (status == BRCMF_E_STATUS_SUCCESS) {
- BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name,
- eabuf));
- } else if (status == BRCMF_E_STATUS_FAIL) {
- BRCMF_EVENT(("MACEVENT: %s, failed\n", event_name));
- } else if (status == BRCMF_E_STATUS_NO_NETWORKS) {
- BRCMF_EVENT(("MACEVENT: %s, no networks found\n",
- event_name));
- } else {
- BRCMF_EVENT(("MACEVENT: %s, unexpected status %d\n",
- event_name, (int)status));
- }
+ if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n",
+ event_name, eabuf);
+ else if (status == BRCMF_E_STATUS_FAIL)
+ brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name);
+ else if (status == BRCMF_E_STATUS_NO_NETWORKS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n",
+ event_name);
+ else
+ brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n",
+ event_name, (int)status);
break;
case BRCMF_E_BEACON_RX:
- if (status == BRCMF_E_STATUS_SUCCESS) {
- BRCMF_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
- } else if (status == BRCMF_E_STATUS_FAIL) {
- BRCMF_EVENT(("MACEVENT: %s, FAIL\n", event_name));
- } else {
- BRCMF_EVENT(("MACEVENT: %s, status %d\n", event_name,
- status));
- }
+ if (status == BRCMF_E_STATUS_SUCCESS)
+ brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name);
+ else if (status == BRCMF_E_STATUS_FAIL)
+ brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name);
+ else
+ brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n",
+ event_name, status);
break;
case BRCMF_E_LINK:
- BRCMF_EVENT(("MACEVENT: %s %s\n", event_name,
- link ? "UP" : "DOWN"));
+ brcmf_dbg(EVENT, "MACEVENT: %s %s\n",
+ event_name, link ? "UP" : "DOWN");
break;
case BRCMF_E_MIC_ERROR:
- BRCMF_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
- event_name, eabuf, group, flush_txq));
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
+ event_name, eabuf, group, flush_txq);
break;
case BRCMF_E_ICV_ERROR:
case BRCMF_E_UNICAST_DECODE_ERROR:
case BRCMF_E_MULTICAST_DECODE_ERROR:
- BRCMF_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
+ brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
break;
case BRCMF_E_TXFAIL:
- BRCMF_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
+ brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf);
break;
case BRCMF_E_SCAN_COMPLETE:
case BRCMF_E_PMKID_CACHE:
- BRCMF_EVENT(("MACEVENT: %s\n", event_name));
+ brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
break;
case BRCMF_E_PFN_NET_FOUND:
case BRCMF_E_PFN_NET_LOST:
case BRCMF_E_PFN_SCAN_COMPLETE:
- BRCMF_EVENT(("PNOEVENT: %s\n", event_name));
+ brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name);
break;
case BRCMF_E_PSK_SUP:
case BRCMF_E_PRUNE:
- BRCMF_EVENT(("MACEVENT: %s, status %d, reason %d\n",
- event_name, (int)status, (int)reason));
+ brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n",
+ event_name, (int)status, (int)reason);
break;
case BRCMF_E_TRACE:
- {
- static u32 seqnum_prev;
- struct msgtrace_hdr hdr;
- u32 nblost;
- char *s, *p;
-
- buf = (unsigned char *) event_data;
- memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
-
- if (hdr.version != MSGTRACE_VERSION) {
- BRCMF_ERROR(
- ("\nMACEVENT: %s [unsupported version --> "
- "brcmf version:%d dongle version:%d]\n",
- event_name, MSGTRACE_VERSION, hdr.version)
- );
- /* Reset datalen to avoid display below */
- datalen = 0;
- break;
- }
-
- /* There are 2 bytes available at the end of data */
- *(buf + sizeof(struct msgtrace_hdr)
- + be16_to_cpu(hdr.len)) = '\0';
-
- if (be32_to_cpu(hdr.discarded_bytes)
- || be32_to_cpu(hdr.discarded_printf)) {
- BRCMF_ERROR(
- ("\nWLC_E_TRACE: [Discarded traces in dongle -->"
- "discarded_bytes %d discarded_printf %d]\n",
- be32_to_cpu(hdr.discarded_bytes),
- be32_to_cpu(hdr.discarded_printf)));
- }
-
- nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
- if (nblost > 0) {
- BRCMF_ERROR(
- ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
- be32_to_cpu(hdr.seqnum), nblost));
- }
- seqnum_prev = be32_to_cpu(hdr.seqnum);
-
- /* Display the trace buffer. Advance from \n to \n to
- * avoid display big
- * printf (issue with Linux printk )
- */
- p = (char *)&buf[sizeof(struct msgtrace_hdr)];
- while ((s = strstr(p, "\n")) != NULL) {
- *s = '\0';
- printk(KERN_DEBUG"%s\n", p);
- p = s + 1;
- }
- printk(KERN_DEBUG "%s\n", p);
+ buf = (unsigned char *) event_data;
+ memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
+ if (hdr.version != MSGTRACE_VERSION) {
+ brcmf_dbg(ERROR,
+ "MACEVENT: %s [unsupported version --> brcmf"
+ " version:%d dongle version:%d]\n",
+ event_name, MSGTRACE_VERSION, hdr.version);
/* Reset datalen to avoid display below */
datalen = 0;
+ break;
+ }
+
+ /* There are 2 bytes available at the end of data */
+ *(buf + sizeof(struct msgtrace_hdr)
+ + be16_to_cpu(hdr.len)) = '\0';
+
+ if (be32_to_cpu(hdr.discarded_bytes)
+ || be32_to_cpu(hdr.discarded_printf))
+ brcmf_dbg(ERROR,
+ "WLC_E_TRACE: [Discarded traces in dongle -->"
+ " discarded_bytes %d discarded_printf %d]\n",
+ be32_to_cpu(hdr.discarded_bytes),
+ be32_to_cpu(hdr.discarded_printf));
+
+ nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
+ if (nblost > 0)
+ brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum "
+ " %d nblost %d\n", be32_to_cpu(hdr.seqnum),
+ nblost);
+ seqnum_prev = be32_to_cpu(hdr.seqnum);
+
+ /* Display the trace buffer. Advance from \n to \n to
+ * avoid display big
+ * printf (issue with Linux printk )
+ */
+ p = (char *)&buf[sizeof(struct msgtrace_hdr)];
+ while ((s = strstr(p, "\n")) != NULL) {
+ *s = '\0';
+ printk(KERN_DEBUG"%s\n", p);
+ p = s + 1;
}
+ printk(KERN_DEBUG "%s\n", p);
+
+ /* Reset datalen to avoid display below */
+ datalen = 0;
break;
case BRCMF_E_RSSI:
- BRCMF_EVENT(("MACEVENT: %s %d\n", event_name,
- be32_to_cpu(*((int *)event_data))));
+ brcmf_dbg(EVENT, "MACEVENT: %s %d\n",
+ event_name, be32_to_cpu(*((__be32 *)event_data)));
break;
default:
- BRCMF_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
- "auth %d\n", event_name, event_type, eabuf,
- (int)status, (int)reason, (int)auth_type));
+ brcmf_dbg(EVENT,
+ "MACEVENT: %s %d, MAC %s, status %d, reason %d, "
+ "auth %d\n", event_name, event_type, eabuf,
+ (int)status, (int)reason, (int)auth_type);
break;
}
/* show any appended data */
if (datalen) {
buf = (unsigned char *) event_data;
- BRCMF_EVENT((" data (%d) : ", datalen));
+ brcmf_dbg(EVENT, " data (%d) : ", datalen);
for (i = 0; i < datalen; i++)
- BRCMF_EVENT((" 0x%02x ", *buf++));
- BRCMF_EVENT(("\n"));
+ brcmf_dbg(EVENT, " 0x%02x ", *buf++);
+ brcmf_dbg(EVENT, "\n");
}
}
-#endif /* SHOW_EVENTS */
+#endif /* BCMDBG */
int
brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
@@ -744,20 +451,21 @@ brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
{
/* check whether packet is a BRCM event pkt */
struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
+ struct brcmf_if_event *ifevent;
char *event_data;
u32 type, status;
u16 flags;
int evlen;
if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
- BRCMF_ERROR(("%s: mismatched OUI, bailing\n", __func__));
+ brcmf_dbg(ERROR, "mismatched OUI, bailing\n");
return -EBADE;
}
/* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
BCMILCP_BCM_SUBTYPE_EVENT) {
- BRCMF_ERROR(("%s: mismatched subtype, bailing\n", __func__));
+ brcmf_dbg(ERROR, "mismatched subtype, bailing\n");
return -EBADE;
}
@@ -775,27 +483,22 @@ brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
switch (type) {
case BRCMF_E_IF:
- {
- struct brcmf_if_event *ifevent =
- (struct brcmf_if_event *) event_data;
- BRCMF_TRACE(("%s: if event\n", __func__));
-
- if (ifevent->ifidx > 0 &&
- ifevent->ifidx < BRCMF_MAX_IFS) {
- if (ifevent->action == BRCMF_E_IF_ADD)
- brcmf_add_if(drvr_priv, ifevent->ifidx,
- NULL, event->ifname,
- pvt_data->eth.h_dest,
- ifevent->flags,
- ifevent->bssidx);
- else
- brcmf_del_if(drvr_priv, ifevent->ifidx);
- } else {
- BRCMF_ERROR(("%s: Invalid ifidx %d for %s\n",
- __func__, ifevent->ifidx,
- event->ifname));
- }
+ ifevent = (struct brcmf_if_event *) event_data;
+ brcmf_dbg(TRACE, "if event\n");
+
+ if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
+ if (ifevent->action == BRCMF_E_IF_ADD)
+ brcmf_add_if(drvr_priv, ifevent->ifidx, NULL,
+ event->ifname,
+ pvt_data->eth.h_dest,
+ ifevent->flags, ifevent->bssidx);
+ else
+ brcmf_del_if(drvr_priv, ifevent->ifidx);
+ } else {
+ brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
+ ifevent->ifidx, event->ifname);
}
+
/* send up the if event: btamp user needs it */
*ifidx = brcmf_ifname2idx(drvr_priv, event->ifname);
break;
@@ -810,27 +513,28 @@ brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
/* Fall through: this should get _everything_ */
*ifidx = brcmf_ifname2idx(drvr_priv, event->ifname);
- BRCMF_TRACE(("%s: MAC event %d, flags %x, status %x\n",
- __func__, type, flags, status));
+ brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n",
+ type, flags, status);
/* put it back to BRCMF_E_NDIS_LINK */
if (type == BRCMF_E_NDIS_LINK) {
- u32 temp;
+ u32 temp1;
+ __be32 temp2;
- temp = get_unaligned_be32(&event->event_type);
- BRCMF_TRACE(("Converted to WLC_E_LINK type %d\n",
- temp));
+ temp1 = get_unaligned_be32(&event->event_type);
+ brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n",
+ temp1);
- temp = be32_to_cpu(BRCMF_E_NDIS_LINK);
- memcpy((void *)(&pvt_data->msg.event_type), &temp,
+ temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK);
+ memcpy((void *)(&pvt_data->msg.event_type), &temp2,
sizeof(pvt_data->msg.event_type));
}
break;
}
-#ifdef SHOW_EVENTS
+#ifdef BCMDBG
brcmf_c_show_host_event(event, event_data);
-#endif /* SHOW_EVENTS */
+#endif /* BCMDBG */
return 0;
}
@@ -840,19 +544,22 @@ static int brcmf_c_pattern_atoh(char *src, char *dst)
{
int i;
if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
- BRCMF_ERROR(("Mask invalid format. Needs to start with 0x\n"));
- return -1;
+ brcmf_dbg(ERROR, "Mask invalid format. Needs to start with 0x\n");
+ return -EINVAL;
}
src = src + 2; /* Skip past 0x */
if (strlen(src) % 2 != 0) {
- BRCMF_ERROR(("Mask invalid format. Length must be even.\n"));
- return -1;
+ brcmf_dbg(ERROR, "Mask invalid format. Length must be even.\n");
+ return -EINVAL;
}
for (i = 0; *src != '\0'; i++) {
+ unsigned long res;
char num[3];
strncpy(num, src, 2);
num[2] = '\0';
- dst[i] = (u8) simple_strtoul(num, NULL, 16);
+ if (kstrtoul(num, 16, &res))
+ return -EINVAL;
+ dst[i] = (u8)res;
src += 2;
}
return i;
@@ -862,22 +569,23 @@ void
brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable,
int master_mode)
{
+ unsigned long res;
char *argv[8];
int i = 0;
const char *str;
int buf_len;
int str_len;
- char *arg_save = 0, *arg_org = 0;
+ char *arg_save = NULL, *arg_org = NULL;
int rc;
char buf[128];
- struct brcmf_pkt_filter_enable enable_parm;
- struct brcmf_pkt_filter_enable *pkt_filterp;
+ struct brcmf_pkt_filter_enable_le enable_parm;
+ struct brcmf_pkt_filter_enable_le *pkt_filterp;
+ __le32 mmode_le;
arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
- if (!arg_save) {
- BRCMF_ERROR(("%s: kmalloc failed\n", __func__));
+ if (!arg_save)
goto fail;
- }
+
arg_org = arg_save;
memcpy(arg_save, arg, strlen(arg) + 1);
@@ -885,7 +593,7 @@ brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable,
i = 0;
if (NULL == argv[i]) {
- BRCMF_ERROR(("No args provided\n"));
+ brcmf_dbg(ERROR, "No args provided\n");
goto fail;
}
@@ -895,36 +603,38 @@ brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable,
buf[str_len] = '\0';
buf_len = str_len + 1;
- pkt_filterp = (struct brcmf_pkt_filter_enable *) (buf + str_len + 1);
+ pkt_filterp = (struct brcmf_pkt_filter_enable_le *) (buf + str_len + 1);
/* Parse packet filter id. */
- enable_parm.id = simple_strtoul(argv[i], NULL, 0);
+ enable_parm.id = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ enable_parm.id = cpu_to_le32((u32)res);
/* Parse enable/disable value. */
- enable_parm.enable = enable;
+ enable_parm.enable = cpu_to_le32(enable);
buf_len += sizeof(enable_parm);
memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
/* Enable/disable the specified filter. */
- rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
+ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
rc = rc >= 0 ? 0 : rc;
if (rc)
- BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
- __func__, arg, rc));
+ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
+ arg, rc);
else
- BRCMF_TRACE(("%s: successfully added pktfilter %s\n",
- __func__, arg));
+ brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg);
/* Contorl the master mode */
- brcmu_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf,
+ mmode_le = cpu_to_le32(master_mode);
+ brcmf_c_mkiovar("pkt_filter_mode", (char *)&mmode_le, 4, buf,
sizeof(buf));
- rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf,
+ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf,
sizeof(buf));
rc = rc >= 0 ? 0 : rc;
if (rc)
- BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
- __func__, arg, rc));
+ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
+ arg, rc);
fail:
kfree(arg_org);
@@ -933,32 +643,27 @@ fail:
void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
{
const char *str;
- struct brcmf_pkt_filter pkt_filter;
- struct brcmf_pkt_filter *pkt_filterp;
+ struct brcmf_pkt_filter_le pkt_filter;
+ struct brcmf_pkt_filter_le *pkt_filterp;
+ unsigned long res;
int buf_len;
int str_len;
int rc;
u32 mask_size;
u32 pattern_size;
- char *argv[8], *buf = 0;
+ char *argv[8], *buf = NULL;
int i = 0;
- char *arg_save = 0, *arg_org = 0;
+ char *arg_save = NULL, *arg_org = NULL;
- arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC);
- if (!arg_save) {
- BRCMF_ERROR(("%s: kmalloc failed\n", __func__));
+ arg_save = kstrdup(arg, GFP_ATOMIC);
+ if (!arg_save)
goto fail;
- }
arg_org = arg_save;
buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC);
- if (!buf) {
- BRCMF_ERROR(("%s: kmalloc failed\n", __func__));
+ if (!buf)
goto fail;
- }
-
- strcpy(arg_save, arg);
argv[i] = strsep(&arg_save, " ");
while (argv[i++])
@@ -966,7 +671,7 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
i = 0;
if (NULL == argv[i]) {
- BRCMF_ERROR(("No args provided\n"));
+ brcmf_dbg(ERROR, "No args provided\n");
goto fail;
}
@@ -975,37 +680,45 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
str_len = strlen(str);
buf_len = str_len + 1;
- pkt_filterp = (struct brcmf_pkt_filter *) (buf + str_len + 1);
+ pkt_filterp = (struct brcmf_pkt_filter_le *) (buf + str_len + 1);
/* Parse packet filter id. */
- pkt_filter.id = simple_strtoul(argv[i], NULL, 0);
+ pkt_filter.id = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.id = cpu_to_le32((u32)res);
if (NULL == argv[++i]) {
- BRCMF_ERROR(("Polarity not provided\n"));
+ brcmf_dbg(ERROR, "Polarity not provided\n");
goto fail;
}
/* Parse filter polarity. */
- pkt_filter.negate_match = simple_strtoul(argv[i], NULL, 0);
+ pkt_filter.negate_match = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.negate_match = cpu_to_le32((u32)res);
if (NULL == argv[++i]) {
- BRCMF_ERROR(("Filter type not provided\n"));
+ brcmf_dbg(ERROR, "Filter type not provided\n");
goto fail;
}
/* Parse filter type. */
- pkt_filter.type = simple_strtoul(argv[i], NULL, 0);
+ pkt_filter.type = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.type = cpu_to_le32((u32)res);
if (NULL == argv[++i]) {
- BRCMF_ERROR(("Offset not provided\n"));
+ brcmf_dbg(ERROR, "Offset not provided\n");
goto fail;
}
/* Parse pattern filter offset. */
- pkt_filter.u.pattern.offset = simple_strtoul(argv[i], NULL, 0);
+ pkt_filter.u.pattern.offset = 0;
+ if (!kstrtoul(argv[i], 0, &res))
+ pkt_filter.u.pattern.offset = cpu_to_le32((u32)res);
if (NULL == argv[++i]) {
- BRCMF_ERROR(("Bitmask not provided\n"));
+ brcmf_dbg(ERROR, "Bitmask not provided\n");
goto fail;
}
@@ -1015,7 +728,7 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
(argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern);
if (NULL == argv[++i]) {
- BRCMF_ERROR(("Pattern not provided\n"));
+ brcmf_dbg(ERROR, "Pattern not provided\n");
goto fail;
}
@@ -1026,11 +739,11 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
mask_and_pattern[mask_size]);
if (mask_size != pattern_size) {
- BRCMF_ERROR(("Mask and pattern not the same size\n"));
+ brcmf_dbg(ERROR, "Mask and pattern not the same size\n");
goto fail;
}
- pkt_filter.u.pattern.size_bytes = mask_size;
+ pkt_filter.u.pattern.size_bytes = cpu_to_le32(mask_size);
buf_len += BRCMF_PKT_FILTER_FIXED_LEN;
buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
@@ -1043,15 +756,14 @@ void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg)
&pkt_filter,
BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN);
- rc = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
+ rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len);
rc = rc >= 0 ? 0 : rc;
if (rc)
- BRCMF_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
- __func__, arg, rc));
+ brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n",
+ arg, rc);
else
- BRCMF_TRACE(("%s: successfully added pktfilter %s\n",
- __func__, arg));
+ brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg);
fail:
kfree(arg_org);
@@ -1059,49 +771,50 @@ fail:
kfree(buf);
}
-void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode)
+static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode)
{
char iovbuf[32];
int retcode;
- brcmu_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
- retcode = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR,
+ brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
+ retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
iovbuf, sizeof(iovbuf));
retcode = retcode >= 0 ? 0 : retcode;
if (retcode)
- BRCMF_TRACE(("%s: failed to set ARP offload mode to 0x%x, "
- "retcode = %d\n", __func__, arp_mode, retcode));
+ brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n",
+ arp_mode, retcode);
else
- BRCMF_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
- __func__, arp_mode));
+ brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n",
+ arp_mode);
}
-void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable)
+static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable)
{
char iovbuf[32];
int retcode;
- brcmu_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
- retcode = brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR,
+ brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4,
+ iovbuf, sizeof(iovbuf));
+ retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR,
iovbuf, sizeof(iovbuf));
retcode = retcode >= 0 ? 0 : retcode;
if (retcode)
- BRCMF_TRACE(("%s: failed to enabe ARP offload to %d, "
- "retcode = %d\n", __func__, arp_enable, retcode));
+ brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n",
+ arp_enable, retcode);
else
- BRCMF_TRACE(("%s: successfully enabed ARP offload to %d\n",
- __func__, arp_enable));
+ brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n",
+ arp_enable);
}
-int brcmf_c_preinit_ioctls(struct brcmf_pub *drvr)
+int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr)
{
char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for
"event_msgs" + '\0' + bitvec */
uint up = 0;
char buf[128], *ptr;
- uint power_mode = PM_FAST;
u32 dongle_align = BRCMF_SDALIGN;
u32 glom = 0;
+ u32 roaming = 1;
uint bcn_timeout = 3;
int scan_assoc_time = 40;
int scan_unassoc_time = 40;
@@ -1111,83 +824,69 @@ int brcmf_c_preinit_ioctls(struct brcmf_pub *drvr)
/* Set Country code */
if (drvr->country_code[0] != 0) {
- if (brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_COUNTRY,
- drvr->country_code,
- sizeof(drvr->country_code)) < 0) {
- BRCMF_ERROR(("%s: country code setting failed\n",
- __func__));
- }
+ if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY,
+ drvr->country_code,
+ sizeof(drvr->country_code)) < 0)
+ brcmf_dbg(ERROR, "country code setting failed\n");
}
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
ptr = buf;
- brcmu_mkiovar("ver", 0, 0, buf, sizeof(buf));
- brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf));
+ brcmf_c_mkiovar("ver", NULL, 0, buf, sizeof(buf));
+ brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf));
strsep(&ptr, "\n");
/* Print fw version info */
- BRCMF_ERROR(("Firmware version = %s\n", buf));
-
- /* Set PowerSave mode */
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_PM, (char *)&power_mode,
- sizeof(power_mode));
+ brcmf_dbg(ERROR, "Firmware version = %s\n", buf);
/* Match Host and Dongle rx alignment */
- brcmu_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
+ brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
sizeof(iovbuf));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
sizeof(iovbuf));
/* disable glom option per default */
- brcmu_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
sizeof(iovbuf));
/* Setup timeout if Beacons are lost and roam is off to report
link down */
- brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
+ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
sizeof(iovbuf));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
sizeof(iovbuf));
/* Enable/Disable build-in roaming to allowed ext supplicant to take
of romaing */
- brcmu_mkiovar("roam_off", (char *)&brcmf_roam, 4,
+ brcmf_c_mkiovar("roam_off", (char *)&roaming, 4,
iovbuf, sizeof(iovbuf));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
sizeof(iovbuf));
/* Force STA UP */
- if (brcmf_radio_up)
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_UP, (char *)&up,
- sizeof(up));
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up));
/* Setup event_msgs */
- brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
+ brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
iovbuf, sizeof(iovbuf));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf,
sizeof(iovbuf));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME,
(char *)&scan_assoc_time, sizeof(scan_assoc_time));
- brcmf_proto_cdc_set_ioctl(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+ brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME,
(char *)&scan_unassoc_time, sizeof(scan_unassoc_time));
/* Set and enable ARP offload feature */
- if (brcmf_arp_enable)
- brcmf_c_arp_offload_set(drvr, brcmf_arp_mode);
- brcmf_c_arp_offload_enable(drvr, brcmf_arp_enable);
+ brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE);
+ brcmf_c_arp_offload_enable(drvr, true);
/* Set up pkt filter */
- if (brcmf_pkt_filter_enable) {
- for (i = 0; i < drvr->pktfilter_count; i++) {
- brcmf_c_pktfilter_offload_set(drvr,
- drvr->pktfilter[i]);
- brcmf_c_pktfilter_offload_enable(drvr,
- drvr->pktfilter[i],
- brcmf_pkt_filter_init,
- brcmf_master_mode);
- }
+ for (i = 0; i < drvr->pktfilter_count; i++) {
+ brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]);
+ brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i],
+ 0, true);
}
brcmf_os_proto_unblock(drvr);
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h b/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h
index 5be4d7a609c2..7467922f0536 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_dbg.h
@@ -19,25 +19,21 @@
#if defined(BCMDBG)
-#define BRCMF_ERROR(args) \
- do {if ((brcmf_msg_level & BRCMF_ERROR_VAL) && (net_ratelimit())) \
- printk args; } while (0)
-#define BRCMF_TRACE(args) do {if (brcmf_msg_level & BRCMF_TRACE_VAL) \
- printk args; } while (0)
-#define BRCMF_INFO(args) do {if (brcmf_msg_level & BRCMF_INFO_VAL) \
- printk args; } while (0)
-#define BRCMF_DATA(args) do {if (brcmf_msg_level & BRCMF_DATA_VAL) \
- printk args; } while (0)
-#define BRCMF_CTL(args) do {if (brcmf_msg_level & BRCMF_CTL_VAL) \
- printk args; } while (0)
-#define BRCMF_TIMER(args) do {if (brcmf_msg_level & BRCMF_TIMER_VAL) \
- printk args; } while (0)
-#define BRCMF_INTR(args) do {if (brcmf_msg_level & BRCMF_INTR_VAL) \
- printk args; } while (0)
-#define BRCMF_GLOM(args) do {if (brcmf_msg_level & BRCMF_GLOM_VAL) \
- printk args; } while (0)
-#define BRCMF_EVENT(args) do {if (brcmf_msg_level & BRCMF_EVENT_VAL) \
- printk args; } while (0)
+#define brcmf_dbg(level, fmt, ...) \
+do { \
+ if (BRCMF_ERROR_VAL == BRCMF_##level##_VAL) { \
+ if (brcmf_msg_level & BRCMF_##level##_VAL) { \
+ if (net_ratelimit()) \
+ printk(KERN_DEBUG "%s: " fmt, \
+ __func__, ##__VA_ARGS__); \
+ } \
+ } else { \
+ if (brcmf_msg_level & BRCMF_##level##_VAL) { \
+ printk(KERN_DEBUG "%s: " fmt, \
+ __func__, ##__VA_ARGS__); \
+ } \
+ } \
+} while (0)
#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL)
#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL)
@@ -47,20 +43,12 @@
#else /* (defined BCMDBG) || (defined BCMDBG) */
-#define BRCMF_ERROR(args) do {if (net_ratelimit()) printk args; } while (0)
-#define BRCMF_TRACE(args)
-#define BRCMF_INFO(args)
-#define BRCMF_DATA(args)
-#define BRCMF_CTL(args)
-#define BRCMF_TIMER(args)
-#define BRCMF_INTR(args)
-#define BRCMF_GLOM(args)
-#define BRCMF_EVENT(args)
+#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#define BRCMF_DATA_ON() 0
#define BRCMF_CTL_ON() 0
#define BRCMF_HDRS_ON() 0
-#define BRCMF_BYTES_ON() 0
+#define BRCMF_BYTES_ON() 0
#define BRCMF_GLOM_ON() 0
#endif /* defined(BCMDBG) */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
index 05dada98eb6b..4acbac5a74c6 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c
@@ -28,9 +28,12 @@
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
-#include <linux/interrupt.h>
#include <linux/hardirq.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/module.h>
#include <net/cfg80211.h>
+#include <net/rtnetlink.h>
#include <defs.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
@@ -42,11 +45,6 @@
#include "wl_cfg80211.h"
#include "bcmchip.h"
-#if defined(CONFIG_PM_SLEEP)
-#include <linux/suspend.h>
-atomic_t brcmf_mmc_suspend;
-#endif /* defined(CONFIG_PM_SLEEP) */
-
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
@@ -57,15 +55,11 @@ MODULE_LICENSE("Dual BSD/GPL");
struct brcmf_if {
struct brcmf_info *info; /* back pointer to brcmf_info */
/* OS/stack specifics */
- struct net_device *net;
+ struct net_device *ndev;
struct net_device_stats stats;
int idx; /* iface idx in dongle */
int state; /* interface state */
- uint subunit; /* subunit */
u8 mac_addr[ETH_ALEN]; /* assigned MAC address */
- bool attached; /* Delayed attachment when unset */
- bool txflowcontrol; /* Per interface flow control indicator */
- char name[IFNAMSIZ]; /* linux interface name */
};
/* Local private structure (extension of pub) */
@@ -75,14 +69,10 @@ struct brcmf_info {
/* OS/stack specifics */
struct brcmf_if *iflist[BRCMF_MAX_IFS];
- struct semaphore proto_sem;
- wait_queue_head_t ioctl_resp_wait;
+ struct mutex proto_block;
- /* Thread to issue ioctl for multicast */
- struct task_struct *sysioc_tsk;
- struct semaphore sysioc_sem;
- bool set_multicast;
- bool set_macaddress;
+ struct work_struct setmacaddr_work;
+ struct work_struct multicast_work;
u8 macvalue[ETH_ALEN];
atomic_t pend_8021x_cnt;
};
@@ -90,148 +80,13 @@ struct brcmf_info {
/* Error bits */
module_param(brcmf_msg_level, int, 0);
-/* Spawn a thread for system ioctls (set mac, set mcast) */
-uint brcmf_sysioc = true;
-module_param(brcmf_sysioc, uint, 0);
-
-/* ARP offload agent mode : Enable ARP Host Auto-Reply
-and ARP Peer Auto-Reply */
-uint brcmf_arp_mode = 0xb;
-module_param(brcmf_arp_mode, uint, 0);
-
-/* ARP offload enable */
-uint brcmf_arp_enable = true;
-module_param(brcmf_arp_enable, uint, 0);
-
-/* Global Pkt filter enable control */
-uint brcmf_pkt_filter_enable = true;
-module_param(brcmf_pkt_filter_enable, uint, 0);
-
-/* Pkt filter init setup */
-uint brcmf_pkt_filter_init;
-module_param(brcmf_pkt_filter_init, uint, 0);
-
-/* Pkt filter mode control */
-uint brcmf_master_mode = true;
-module_param(brcmf_master_mode, uint, 0);
-
-module_param(brcmf_dongle_memsize, int, 0);
-
-/* Contorl fw roaming */
-uint brcmf_roam = 1;
-
-/* Control radio state */
-uint brcmf_radio_up = 1;
-
-/* Network inteface name */
-char iface_name[IFNAMSIZ] = "wlan";
-module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
-
-/* The following are specific to the SDIO dongle */
-
-/* IOCTL response timeout */
-int brcmf_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
-
-/* Idle timeout for backplane clock */
-int brcmf_idletime = BRCMF_IDLETIME_TICKS;
-module_param(brcmf_idletime, int, 0);
-
-/* Use polling */
-uint brcmf_poll;
-module_param(brcmf_poll, uint, 0);
-/* Use interrupts */
-uint brcmf_intr = true;
-module_param(brcmf_intr, uint, 0);
-
-/* SDIO Drive Strength (in milliamps) */
-uint brcmf_sdiod_drive_strength = 6;
-module_param(brcmf_sdiod_drive_strength, uint, 0);
-
-/* Tx/Rx bounds */
-module_param(brcmf_txbound, uint, 0);
-module_param(brcmf_rxbound, uint, 0);
-
-#ifdef SDTEST
-/* Echo packet generator (pkts/s) */
-uint brcmf_pktgen;
-module_param(brcmf_pktgen, uint, 0);
-
-/* Echo packet len (0 => sawtooth, max 2040) */
-uint brcmf_pktgen_len;
-module_param(brcmf_pktgen_len, uint, 0);
-#endif
-
-static int brcmf_toe_get(struct brcmf_info *drvr_priv, int idx, u32 *toe_ol);
-static int brcmf_toe_set(struct brcmf_info *drvr_priv, int idx, u32 toe_ol);
-static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
- struct brcmf_event_msg *event_ptr,
- void **data_ptr);
-
-/*
- * Generalized timeout mechanism. Uses spin sleep with exponential
- * back-off until
- * the sleep time reaches one jiffy, then switches over to task delay. Usage:
- *
- * brcmf_timeout_start(&tmo, usec);
- * while (!brcmf_timeout_expired(&tmo))
- * if (poll_something())
- * break;
- * if (brcmf_timeout_expired(&tmo))
- * fatal();
- */
-
-void brcmf_timeout_start(struct brcmf_timeout *tmo, uint usec)
-{
- tmo->limit = usec;
- tmo->increment = 0;
- tmo->elapsed = 0;
- tmo->tick = 1000000 / HZ;
-}
-
-int brcmf_timeout_expired(struct brcmf_timeout *tmo)
-{
- /* Does nothing the first call */
- if (tmo->increment == 0) {
- tmo->increment = 1;
- return 0;
- }
-
- if (tmo->elapsed >= tmo->limit)
- return 1;
-
- /* Add the delay that's about to take place */
- tmo->elapsed += tmo->increment;
-
- if (tmo->increment < tmo->tick) {
- udelay(tmo->increment);
- tmo->increment *= 2;
- if (tmo->increment > tmo->tick)
- tmo->increment = tmo->tick;
- } 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;
-}
-
-static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *net)
+static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev)
{
int i = 0;
while (i < BRCMF_MAX_IFS) {
- if (drvr_priv->iflist[i] && (drvr_priv->iflist[i]->net == net))
+ if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev)
return i;
i++;
}
@@ -242,16 +97,18 @@ static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *net)
int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
{
int i = BRCMF_MAX_IFS;
+ struct brcmf_if *ifp;
if (name == NULL || *name == '\0')
return 0;
- while (--i > 0)
- if (drvr_priv->iflist[i]
- && !strncmp(drvr_priv->iflist[i]->name, name, IFNAMSIZ))
+ while (--i > 0) {
+ ifp = drvr_priv->iflist[i];
+ if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
break;
+ }
- BRCMF_TRACE(("%s: return idx %d for \"%s\"\n", __func__, i, name));
+ brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name);
return i; /* default - the primary interface */
}
@@ -261,56 +118,58 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
struct brcmf_info *drvr_priv = drvr->info;
if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
- BRCMF_ERROR(("%s: ifidx %d out of range\n", __func__, ifidx));
+ brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx);
return "<if_bad>";
}
if (drvr_priv->iflist[ifidx] == NULL) {
- BRCMF_ERROR(("%s: null i/f %d\n", __func__, ifidx));
+ brcmf_dbg(ERROR, "null i/f %d\n", ifidx);
return "<if_null>";
}
- if (drvr_priv->iflist[ifidx]->net)
- return drvr_priv->iflist[ifidx]->net->name;
+ if (drvr_priv->iflist[ifidx]->ndev)
+ return drvr_priv->iflist[ifidx]->ndev->name;
return "<if_none>";
}
-static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
+static void _brcmf_set_multicast_list(struct work_struct *work)
{
- struct net_device *dev;
+ struct net_device *ndev;
struct netdev_hw_addr *ha;
- u32 allmulti, cnt;
+ u32 dcmd_value, cnt;
+ __le32 cnt_le;
+ __le32 dcmd_le_value;
- struct brcmf_ioctl ioc;
+ struct brcmf_dcmd dcmd;
char *buf, *bufp;
uint buflen;
int ret;
- dev = drvr_priv->iflist[ifidx]->net;
- cnt = netdev_mc_count(dev);
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+ multicast_work);
+
+ ndev = drvr_priv->iflist[0]->ndev;
+ cnt = netdev_mc_count(ndev);
/* Determine initial value of allmulti flag */
- allmulti = (dev->flags & IFF_ALLMULTI) ? true : false;
+ dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
/* Send down the multicast list first. */
buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
bufp = buf = kmalloc(buflen, GFP_ATOMIC);
- if (!bufp) {
- BRCMF_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), cnt));
+ if (!bufp)
return;
- }
strcpy(bufp, "mcast_list");
bufp += strlen("mcast_list") + 1;
- cnt = cpu_to_le32(cnt);
- memcpy(bufp, &cnt, sizeof(cnt));
- bufp += sizeof(cnt);
+ cnt_le = cpu_to_le32(cnt);
+ memcpy(bufp, &cnt_le, sizeof(cnt));
+ bufp += sizeof(cnt_le);
- netdev_for_each_mc_addr(ha, dev) {
+ netdev_for_each_mc_addr(ha, ndev) {
if (!cnt)
break;
memcpy(bufp, ha->addr, ETH_ALEN);
@@ -318,17 +177,17 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
cnt--;
}
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = BRCMF_C_SET_VAR;
- ioc.buf = buf;
- ioc.len = buflen;
- ioc.set = true;
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = buflen;
+ dcmd.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
if (ret < 0) {
- BRCMF_ERROR(("%s: set mcast_list failed, cnt %d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), cnt));
- allmulti = cnt ? true : allmulti;
+ brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
+ brcmf_ifname(&drvr_priv->pub, 0), cnt);
+ dcmd_value = cnt ? true : dcmd_value;
}
kfree(buf);
@@ -338,36 +197,34 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
* were trying to set some addresses and dongle rejected it...
*/
- buflen = sizeof("allmulti") + sizeof(allmulti);
+ buflen = sizeof("allmulti") + sizeof(dcmd_value);
buf = kmalloc(buflen, GFP_ATOMIC);
- if (!buf) {
- BRCMF_ERROR(("%s: out of memory for allmulti\n",
- brcmf_ifname(&drvr_priv->pub, ifidx)));
+ if (!buf)
return;
- }
- allmulti = cpu_to_le32(allmulti);
-
- if (!brcmu_mkiovar
- ("allmulti", (void *)&allmulti, sizeof(allmulti), buf, buflen)) {
- BRCMF_ERROR(("%s: mkiovar failed for allmulti, datalen %d "
- "buflen %u\n",
- brcmf_ifname(&drvr_priv->pub, ifidx),
- (int)sizeof(allmulti), buflen));
+
+ dcmd_le_value = cpu_to_le32(dcmd_value);
+
+ if (!brcmf_c_mkiovar
+ ("allmulti", (void *)&dcmd_le_value,
+ sizeof(dcmd_le_value), buf, buflen)) {
+ brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
+ brcmf_ifname(&drvr_priv->pub, 0),
+ (int)sizeof(dcmd_value), buflen);
kfree(buf);
return;
}
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = BRCMF_C_SET_VAR;
- ioc.buf = buf;
- ioc.len = buflen;
- ioc.set = true;
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = buflen;
+ dcmd.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
if (ret < 0) {
- BRCMF_ERROR(("%s: set allmulti %d failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx),
- le32_to_cpu(allmulti)));
+ brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
+ brcmf_ifname(&drvr_priv->pub, 0),
+ le32_to_cpu(dcmd_le_value));
}
kfree(buf);
@@ -375,237 +232,84 @@ static void _brcmf_set_multicast_list(struct brcmf_info *drvr_priv, int ifidx)
/* Finally, pick up the PROMISC flag as well, like the NIC
driver does */
- allmulti = (dev->flags & IFF_PROMISC) ? true : false;
- allmulti = cpu_to_le32(allmulti);
+ dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
+ dcmd_le_value = cpu_to_le32(dcmd_value);
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = BRCMF_C_SET_PROMISC;
- ioc.buf = &allmulti;
- ioc.len = sizeof(allmulti);
- ioc.set = true;
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_PROMISC;
+ dcmd.buf = &dcmd_le_value;
+ dcmd.len = sizeof(dcmd_le_value);
+ dcmd.set = true;
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
if (ret < 0) {
- BRCMF_ERROR(("%s: set promisc %d failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx),
- le32_to_cpu(allmulti)));
+ brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
+ brcmf_ifname(&drvr_priv->pub, 0),
+ le32_to_cpu(dcmd_le_value));
}
}
-static int _brcmf_set_mac_address(struct brcmf_info *drvr_priv, int ifidx, u8 *addr)
+static void
+_brcmf_set_mac_address(struct work_struct *work)
{
char buf[32];
- struct brcmf_ioctl ioc;
+ struct brcmf_dcmd dcmd;
int ret;
- BRCMF_TRACE(("%s enter\n", __func__));
- if (!brcmu_mkiovar
- ("cur_etheraddr", (char *)addr, ETH_ALEN, buf, 32)) {
- BRCMF_ERROR(("%s: mkiovar failed for cur_etheraddr\n",
- brcmf_ifname(&drvr_priv->pub, ifidx)));
- return -1;
- }
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = BRCMF_C_SET_VAR;
- ioc.buf = buf;
- ioc.len = 32;
- ioc.set = true;
-
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
- if (ret < 0) {
- BRCMF_ERROR(("%s: set cur_etheraddr failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx)));
- } else {
- memcpy(drvr_priv->iflist[ifidx]->net->dev_addr, addr, ETH_ALEN);
- }
-
- return ret;
-}
-
-#ifdef SOFTAP
-extern struct net_device *ap_net_dev;
-#endif
-
-/* Virtual interfaces only ((ifp && ifp->info && ifp->idx == true) */
-static void brcmf_op_if(struct brcmf_if *ifp)
-{
- struct brcmf_info *drvr_priv;
- int ret = 0, err = 0;
-
- drvr_priv = ifp->info;
-
- BRCMF_TRACE(("%s: idx %d, state %d\n", __func__, ifp->idx, ifp->state));
-
- switch (ifp->state) {
- case BRCMF_E_IF_ADD:
- /*
- * Delete the existing interface before overwriting it
- * in case we missed the BRCMF_E_IF_DEL event.
- */
- if (ifp->net != NULL) {
- BRCMF_ERROR(("%s: ERROR: netdev:%s already exists, "
- "try free & unregister\n",
- __func__, ifp->net->name));
- netif_stop_queue(ifp->net);
- unregister_netdev(ifp->net);
- free_netdev(ifp->net);
- }
- /* Allocate etherdev, including space for private structure */
- ifp->net = alloc_etherdev(sizeof(drvr_priv));
- if (!ifp->net) {
- BRCMF_ERROR(("%s: OOM - alloc_etherdev\n", __func__));
- ret = -ENOMEM;
- }
- if (ret == 0) {
- strcpy(ifp->net->name, ifp->name);
- memcpy(netdev_priv(ifp->net), &drvr_priv, sizeof(drvr_priv));
- err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
- if (err != 0) {
- BRCMF_ERROR(("%s: brcmf_net_attach failed, "
- "err %d\n",
- __func__, err));
- ret = -EOPNOTSUPP;
- } else {
-#ifdef SOFTAP
- /* semaphore that the soft AP CODE
- waits on */
- extern struct semaphore ap_eth_sema;
-
- /* save ptr to wl0.1 netdev for use
- in wl_iw.c */
- ap_net_dev = ifp->net;
- /* signal to the SOFTAP 'sleeper' thread,
- wl0.1 is ready */
- up(&ap_eth_sema);
-#endif
- BRCMF_TRACE(("\n ==== pid:%x, net_device for "
- "if:%s created ===\n\n",
- current->pid, ifp->net->name));
- ifp->state = 0;
- }
- }
- break;
- case BRCMF_E_IF_DEL:
- if (ifp->net != NULL) {
- BRCMF_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n",
- __func__));
- netif_stop_queue(ifp->net);
- unregister_netdev(ifp->net);
- ret = BRCMF_DEL_IF; /* Make sure the free_netdev()
- is called */
- }
- break;
- default:
- BRCMF_ERROR(("%s: bad op %d\n", __func__, ifp->state));
- break;
- }
+ struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+ setmacaddr_work);
- if (ret < 0) {
- if (ifp->net)
- free_netdev(ifp->net);
-
- drvr_priv->iflist[ifp->idx] = NULL;
- kfree(ifp);
-#ifdef SOFTAP
- if (ifp->net == ap_net_dev)
- ap_net_dev = NULL; /* NULL SOFTAP global
- wl0.1 as well */
-#endif /* SOFTAP */
+ brcmf_dbg(TRACE, "enter\n");
+ if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue,
+ ETH_ALEN, buf, 32)) {
+ brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
+ brcmf_ifname(&drvr_priv->pub, 0));
+ return;
}
-}
-
-static int _brcmf_sysioc_thread(void *data)
-{
- struct brcmf_info *drvr_priv = (struct brcmf_info *) data;
- int i;
-#ifdef SOFTAP
- bool in_ap = false;
-#endif
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = 32;
+ dcmd.set = true;
- allow_signal(SIGTERM);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+ if (ret < 0)
+ brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
+ brcmf_ifname(&drvr_priv->pub, 0));
+ else
+ memcpy(drvr_priv->iflist[0]->ndev->dev_addr,
+ drvr_priv->macvalue, ETH_ALEN);
- while (down_interruptible(&drvr_priv->sysioc_sem) == 0) {
- if (kthread_should_stop())
- break;
- for (i = 0; i < BRCMF_MAX_IFS; i++) {
- struct brcmf_if *ifentry = drvr_priv->iflist[i];
- if (ifentry) {
-#ifdef SOFTAP
- in_ap = (ap_net_dev != NULL);
-#endif /* SOFTAP */
- if (ifentry->state)
- brcmf_op_if(ifentry);
-#ifdef SOFTAP
- if (drvr_priv->iflist[i] == NULL) {
- BRCMF_TRACE(("\n\n %s: interface %d "
- "removed!\n", __func__,
- i));
- continue;
- }
-
- if (in_ap && drvr_priv->set_macaddress) {
- BRCMF_TRACE(("attempt to set MAC for"
- " %s in AP Mode,"
- " blocked.\n",
- ifentry->net->name));
- drvr_priv->set_macaddress = false;
- continue;
- }
-
- if (in_ap && drvr_priv->set_multicast) {
- BRCMF_TRACE(("attempt to set MULTICAST "
- "list for %s in AP Mode, "
- "blocked.\n",
- ifentry->net->name));
- drvr_priv->set_multicast = false;
- continue;
- }
-#endif /* SOFTAP */
- if (drvr_priv->set_multicast) {
- drvr_priv->set_multicast = false;
- _brcmf_set_multicast_list(drvr_priv, i);
- }
- if (drvr_priv->set_macaddress) {
- drvr_priv->set_macaddress = false;
- _brcmf_set_mac_address(drvr_priv, i,
- drvr_priv->macvalue);
- }
- }
- }
- }
- return 0;
+ return;
}
-static int brcmf_netdev_set_mac_address(struct net_device *dev, void *addr)
+static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{
- int ret = 0;
-
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
struct sockaddr *sa = (struct sockaddr *)addr;
int ifidx;
- ifidx = brcmf_net2idx(drvr_priv, dev);
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
if (ifidx == BRCMF_BAD_IF)
return -1;
memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
- drvr_priv->set_macaddress = true;
- up(&drvr_priv->sysioc_sem);
-
- return ret;
+ schedule_work(&drvr_priv->setmacaddr_work);
+ return 0;
}
-static void brcmf_netdev_set_multicast_list(struct net_device *dev)
+static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(dev);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
int ifidx;
- ifidx = brcmf_net2idx(drvr_priv, dev);
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
if (ifidx == BRCMF_BAD_IF)
return;
- drvr_priv->set_multicast = true;
- up(&drvr_priv->sysioc_sem);
+ schedule_work(&drvr_priv->multicast_work);
}
int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
@@ -634,27 +338,27 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf);
}
-static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *net)
+static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
int ret;
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
int ifidx;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* Reject if down */
if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) {
- BRCMF_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n",
- __func__, drvr_priv->pub.up,
- drvr_priv->pub.busstate));
- netif_stop_queue(net);
+ brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n",
+ drvr_priv->pub.up, drvr_priv->pub.busstate);
+ netif_stop_queue(ndev);
return -ENODEV;
}
- ifidx = brcmf_net2idx(drvr_priv, net);
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
if (ifidx == BRCMF_BAD_IF) {
- BRCMF_ERROR(("%s: bad ifidx %d\n", __func__, ifidx));
- netif_stop_queue(net);
+ brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx);
+ netif_stop_queue(ndev);
return -ENODEV;
}
@@ -662,15 +366,15 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *net)
if (skb_headroom(skb) < drvr_priv->pub.hdrlen) {
struct sk_buff *skb2;
- BRCMF_INFO(("%s: insufficient headroom\n",
- brcmf_ifname(&drvr_priv->pub, ifidx)));
+ brcmf_dbg(INFO, "%s: insufficient headroom\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx));
drvr_priv->pub.tx_realloc++;
skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
dev_kfree_skb(skb);
skb = skb2;
if (skb == NULL) {
- BRCMF_ERROR(("%s: skb_realloc_headroom failed\n",
- brcmf_ifname(&drvr_priv->pub, ifidx)));
+ brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx));
ret = -ENOMEM;
goto done;
}
@@ -690,17 +394,34 @@ done:
void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state)
{
- struct net_device *net;
+ struct net_device *ndev;
struct brcmf_info *drvr_priv = drvr->info;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
drvr->txoff = state;
- net = drvr_priv->iflist[ifidx]->net;
+ ndev = drvr_priv->iflist[ifidx]->ndev;
if (state == ON)
- netif_stop_queue(net);
+ netif_stop_queue(ndev);
else
- netif_wake_queue(net);
+ netif_wake_queue(ndev);
+}
+
+static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,
+ void *pktdata, struct brcmf_event_msg *event,
+ void **data)
+{
+ int bcmerror = 0;
+
+ bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data);
+ if (bcmerror != 0)
+ return bcmerror;
+
+ if (drvr_priv->iflist[*ifidx]->ndev)
+ brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev,
+ event, *data);
+
+ return bcmerror;
}
void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
@@ -715,7 +436,7 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
struct brcmf_if *ifp;
struct brcmf_event_msg event;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
save_pktbuf = skb;
@@ -743,7 +464,7 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
if (ifp == NULL)
ifp = drvr_priv->iflist[0];
- skb->dev = ifp->net;
+ skb->dev = ifp->ndev;
skb->protocol = eth_type_trans(skb, skb->dev);
if (skb->pkt_type == PACKET_MULTICAST)
@@ -765,15 +486,15 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
!drvr_priv->iflist[ifidx]->state)
ifp = drvr_priv->iflist[ifidx];
- if (ifp->net)
- ifp->net->last_rx = jiffies;
+ if (ifp->ndev)
+ ifp->ndev->last_rx = jiffies;
drvr->dstats.rx_bytes += skb->len;
drvr->rx_packets++; /* Local count */
- if (in_interrupt()) {
+ if (in_interrupt())
netif_rx(skb);
- } else {
+ else
/* If the receive is not processed inside an ISR,
* the softirqd must be woken explicitly to service
* the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
@@ -781,7 +502,6 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
* to do it manually.
*/
netif_rx_ni(skb);
- }
}
}
@@ -802,24 +522,24 @@ void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
}
-static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net)
+static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
struct brcmf_if *ifp;
int ifidx;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- ifidx = brcmf_net2idx(drvr_priv, net);
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
if (ifidx == BRCMF_BAD_IF)
return NULL;
ifp = drvr_priv->iflist[ifidx];
- if (drvr_priv->pub.up) {
+ if (drvr_priv->pub.up)
/* Use the protocol to get dongle stats */
brcmf_proto_dstats(&drvr_priv->pub);
- }
/* Copy dongle stats to net device stats */
ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets;
@@ -839,33 +559,35 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *net)
as a bitmap in toe_ol iovar */
static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
{
- struct brcmf_ioctl ioc;
+ struct brcmf_dcmd dcmd;
+ __le32 toe_le;
char buf[32];
int ret;
- memset(&ioc, 0, sizeof(ioc));
+ memset(&dcmd, 0, sizeof(dcmd));
- ioc.cmd = BRCMF_C_GET_VAR;
- ioc.buf = buf;
- ioc.len = (uint) sizeof(buf);
- ioc.set = false;
+ dcmd.cmd = BRCMF_C_GET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = (uint) sizeof(buf);
+ dcmd.set = false;
strcpy(buf, "toe_ol");
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
if (ret < 0) {
/* Check for older dongle image that doesn't support toe_ol */
if (ret == -EIO) {
- BRCMF_ERROR(("%s: toe not supported by device\n",
- brcmf_ifname(&drvr_priv->pub, ifidx)));
+ brcmf_dbg(ERROR, "%s: toe not supported by device\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx));
return -EOPNOTSUPP;
}
- BRCMF_INFO(("%s: could not get toe_ol: ret=%d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), ret));
+ brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx), ret);
return ret;
}
- memcpy(toe_ol, buf, sizeof(u32));
+ memcpy(&toe_le, buf, sizeof(u32));
+ *toe_ol = le32_to_cpu(toe_le);
return 0;
}
@@ -873,63 +595,63 @@ static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
and set toe global enable iovar */
static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
{
- struct brcmf_ioctl ioc;
+ struct brcmf_dcmd dcmd;
char buf[32];
- int toe, ret;
+ int ret;
+ __le32 toe_le = cpu_to_le32(toe_ol);
- memset(&ioc, 0, sizeof(ioc));
+ memset(&dcmd, 0, sizeof(dcmd));
- ioc.cmd = BRCMF_C_SET_VAR;
- ioc.buf = buf;
- ioc.len = (uint) sizeof(buf);
- ioc.set = true;
+ dcmd.cmd = BRCMF_C_SET_VAR;
+ dcmd.buf = buf;
+ dcmd.len = (uint) sizeof(buf);
+ dcmd.set = true;
/* Set toe_ol as requested */
-
strcpy(buf, "toe_ol");
- memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(u32));
+ memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
if (ret < 0) {
- BRCMF_ERROR(("%s: could not set toe_ol: ret=%d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), ret));
+ brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx), ret);
return ret;
}
/* Enable toe globally only if any components are enabled. */
-
- toe = (toe_ol != 0);
+ toe_le = cpu_to_le32(toe_ol != 0);
strcpy(buf, "toe");
- memcpy(&buf[sizeof("toe")], &toe, sizeof(u32));
+ memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
- ret = brcmf_proto_ioctl(&drvr_priv->pub, ifidx, &ioc, ioc.buf, ioc.len);
+ ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
if (ret < 0) {
- BRCMF_ERROR(("%s: could not set toe: ret=%d\n",
- brcmf_ifname(&drvr_priv->pub, ifidx), ret));
+ brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
+ brcmf_ifname(&drvr_priv->pub, ifidx), ret);
return ret;
}
return 0;
}
-static void brcmf_ethtool_get_drvinfo(struct net_device *net,
+static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
sprintf(info->driver, KBUILD_MODNAME);
sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
sprintf(info->fw_version, "%s", BCM4329_FW_NAME);
sprintf(info->bus_info, "%s",
- dev_name(&brcmf_cfg80211_get_sdio_func()->dev));
+ dev_name(brcmf_bus_get_device(drvr_priv->pub.bus)));
}
-struct ethtool_ops brcmf_ethtool_ops = {
+static struct ethtool_ops brcmf_ethtool_ops = {
.get_drvinfo = brcmf_ethtool_get_drvinfo
};
-static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
+static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
{
struct ethtool_drvinfo info;
char drvname[sizeof(info.driver)];
@@ -938,7 +660,7 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
u32 toe_cmpnt, csum_dir;
int ret;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* all ethtool calls start with a cmd word */
if (copy_from_user(&cmd, uaddr, sizeof(u32)))
@@ -964,7 +686,7 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
/* otherwise, require dongle to be up */
else if (!drvr_priv->pub.up) {
- BRCMF_ERROR(("%s: dongle is not up\n", __func__));
+ brcmf_dbg(ERROR, "dongle is not up\n");
return -ENODEV;
}
@@ -977,8 +699,8 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
sprintf(info.version, "%lu", drvr_priv->pub.drv_version);
if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT;
- BRCMF_CTL(("%s: given %*s, returning %s\n", __func__,
- (int)sizeof(drvname), drvname, info.driver));
+ brcmf_dbg(CTL, "given %*s, returning %s\n",
+ (int)sizeof(drvname), drvname, info.driver);
break;
/* Get toe offload components from dongle */
@@ -1024,10 +746,10 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
/* If setting TX checksum mode, tell Linux the new mode */
if (cmd == ETHTOOL_STXCSUM) {
if (edata.data)
- drvr_priv->iflist[0]->net->features |=
+ drvr_priv->iflist[0]->ndev->features |=
NETIF_F_IP_CSUM;
else
- drvr_priv->iflist[0]->net->features &=
+ drvr_priv->iflist[0]->ndev->features &=
~NETIF_F_IP_CSUM;
}
@@ -1040,180 +762,131 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void *uaddr)
return 0;
}
-static int brcmf_netdev_ioctl_entry(struct net_device *net, struct ifreq *ifr,
+static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
int cmd)
{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
- struct brcmf_c_ioctl ioc;
- int bcmerror = 0;
- int buflen = 0;
- void *buf = NULL;
- uint driver = 0;
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
int ifidx;
- bool is_set_key_cmd;
- ifidx = brcmf_net2idx(drvr_priv, net);
- BRCMF_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __func__, ifidx, cmd));
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
+ brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd);
if (ifidx == BRCMF_BAD_IF)
return -1;
if (cmd == SIOCETHTOOL)
- return brcmf_ethtool(drvr_priv, (void *)ifr->ifr_data);
-
- if (cmd != SIOCDEVPRIVATE)
- return -EOPNOTSUPP;
-
- memset(&ioc, 0, sizeof(ioc));
+ return brcmf_ethtool(drvr_priv, ifr->ifr_data);
- /* Copy the ioc control structure part of ioctl request */
- if (copy_from_user(&ioc, ifr->ifr_data, sizeof(struct brcmf_ioctl))) {
- bcmerror = -EINVAL;
- goto done;
- }
+ return -EOPNOTSUPP;
+}
- /* Copy out any buffer passed */
- if (ioc.buf) {
- buflen = min_t(int, ioc.len, BRCMF_IOCTL_MAXLEN);
- /* optimization for direct ioctl calls from kernel */
- /*
- if (segment_eq(get_fs(), KERNEL_DS)) {
- buf = ioc.buf;
- } else {
- */
- {
- buf = kmalloc(buflen, GFP_ATOMIC);
- if (!buf) {
- bcmerror = -ENOMEM;
- goto done;
- }
- if (copy_from_user(buf, ioc.buf, buflen)) {
- bcmerror = -EINVAL;
- goto done;
- }
- }
- }
+/* called only from within this driver. Sends a command to the dongle. */
+s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
+{
+ struct brcmf_dcmd dcmd;
+ s32 err = 0;
+ int buflen = 0;
+ bool is_set_key_cmd;
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
+ int ifidx;
- /* To differentiate read 4 more byes */
- if ((copy_from_user(&driver, (char *)ifr->ifr_data +
- sizeof(struct brcmf_ioctl), sizeof(uint)) != 0)) {
- bcmerror = -EINVAL;
- goto done;
- }
+ memset(&dcmd, 0, sizeof(dcmd));
+ dcmd.cmd = cmd;
+ dcmd.buf = arg;
+ dcmd.len = len;
- if (!capable(CAP_NET_ADMIN)) {
- bcmerror = -EPERM;
- goto done;
- }
+ ifidx = brcmf_net2idx(drvr_priv, ndev);
- /* check for local brcmf ioctl and handle it */
- if (driver == BRCMF_IOCTL_MAGIC) {
- bcmerror = brcmf_c_ioctl((void *)&drvr_priv->pub, &ioc, buf, buflen);
- if (bcmerror)
- drvr_priv->pub.bcmerror = bcmerror;
- goto done;
- }
+ if (dcmd.buf != NULL)
+ buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
/* send to dongle (must be up, and wl) */
if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) {
- BRCMF_ERROR(("%s DONGLE_DOWN,__func__\n", __func__));
- bcmerror = -EIO;
+ brcmf_dbg(ERROR, "DONGLE_DOWN\n");
+ err = -EIO;
goto done;
}
if (!drvr_priv->pub.iswl) {
- bcmerror = -EIO;
+ err = -EIO;
goto done;
}
/*
- * Intercept BRCMF_C_SET_KEY IOCTL - serialize M4 send and
- * set key IOCTL to prevent M4 encryption.
+ * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and
+ * set key CMD to prevent M4 encryption.
*/
- is_set_key_cmd = ((ioc.cmd == BRCMF_C_SET_KEY) ||
- ((ioc.cmd == BRCMF_C_SET_VAR) &&
- !(strncmp("wsec_key", ioc.buf, 9))) ||
- ((ioc.cmd == BRCMF_C_SET_VAR) &&
- !(strncmp("bsscfg:wsec_key", ioc.buf, 15))));
+ is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) ||
+ ((dcmd.cmd == BRCMF_C_SET_VAR) &&
+ !(strncmp("wsec_key", dcmd.buf, 9))) ||
+ ((dcmd.cmd == BRCMF_C_SET_VAR) &&
+ !(strncmp("bsscfg:wsec_key", dcmd.buf, 15))));
if (is_set_key_cmd)
- brcmf_netdev_wait_pend8021x(net);
+ brcmf_netdev_wait_pend8021x(ndev);
- bcmerror =
- brcmf_proto_ioctl(&drvr_priv->pub, ifidx, (struct brcmf_ioctl *)&ioc,
- buf, buflen);
+ err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen);
done:
- if (!bcmerror && buf && ioc.buf) {
- if (copy_to_user(ioc.buf, buf, buflen))
- bcmerror = -EFAULT;
- }
-
- kfree(buf);
-
- if (bcmerror > 0)
- bcmerror = 0;
+ if (err > 0)
+ err = 0;
- return bcmerror;
+ return err;
}
-static int brcmf_netdev_stop(struct net_device *net)
+static int brcmf_netdev_stop(struct net_device *ndev)
{
-#if !defined(IGNORE_ETH0_DOWN)
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
+ struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev);
- BRCMF_TRACE(("%s: Enter\n", __func__));
- brcmf_cfg80211_down();
- if (drvr_priv->pub.up == 0)
+ brcmf_dbg(TRACE, "Enter\n");
+ brcmf_cfg80211_down(drvr->config);
+ if (drvr->up == 0)
return 0;
/* Set state and stop OS transmissions */
- drvr_priv->pub.up = 0;
- netif_stop_queue(net);
-#else
- BRCMF_ERROR(("BYPASS %s:due to BRCM compilation: under investigation\n",
- __func__));
-#endif /* !defined(IGNORE_ETH0_DOWN) */
+ drvr->up = 0;
+ netif_stop_queue(ndev);
return 0;
}
-static int brcmf_netdev_open(struct net_device *net)
+static int brcmf_netdev_open(struct net_device *ndev)
{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **) netdev_priv(net);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)
+ netdev_priv(ndev);
u32 toe_ol;
- int ifidx = brcmf_net2idx(drvr_priv, net);
+ int ifidx = brcmf_net2idx(drvr_priv, ndev);
s32 ret = 0;
- BRCMF_TRACE(("%s: ifidx %d\n", __func__, ifidx));
+ brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
if (ifidx == 0) { /* do it only for primary eth0 */
/* try to bring up bus */
ret = brcmf_bus_start(&drvr_priv->pub);
if (ret != 0) {
- BRCMF_ERROR(("%s: failed with code %d\n",
- __func__, ret));
+ brcmf_dbg(ERROR, "failed with code %d\n", ret);
return -1;
}
atomic_set(&drvr_priv->pend_8021x_cnt, 0);
- memcpy(net->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
+ memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
/* Get current TOE mode from dongle */
if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0
&& (toe_ol & TOE_TX_CSUM_OL) != 0)
- drvr_priv->iflist[ifidx]->net->features |=
+ drvr_priv->iflist[ifidx]->ndev->features |=
NETIF_F_IP_CSUM;
else
- drvr_priv->iflist[ifidx]->net->features &=
+ drvr_priv->iflist[ifidx]->ndev->features &=
~NETIF_F_IP_CSUM;
}
/* Allow transmit calls */
- netif_start_queue(net);
+ netif_start_queue(ndev);
drvr_priv->pub.up = 1;
- if (unlikely(brcmf_cfg80211_up())) {
- BRCMF_ERROR(("%s: failed to bring up cfg80211\n",
- __func__));
+ if (brcmf_cfg80211_up(drvr_priv->pub.config)) {
+ brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
return -1;
}
@@ -1221,35 +894,74 @@ static int brcmf_netdev_open(struct net_device *net)
}
int
-brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, void *handle, char *name,
- u8 *mac_addr, u32 flags, u8 bssidx)
+brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev,
+ char *name, u8 *mac_addr, u32 flags, u8 bssidx)
{
struct brcmf_if *ifp;
+ int ret = 0, err = 0;
- BRCMF_TRACE(("%s: idx %d, handle->%p\n", __func__, ifidx, handle));
+ brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev);
ifp = drvr_priv->iflist[ifidx];
if (!ifp) {
ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
- if (!ifp) {
- BRCMF_ERROR(("%s: OOM - struct brcmf_if\n", __func__));
+ if (!ifp)
return -ENOMEM;
- }
}
memset(ifp, 0, sizeof(struct brcmf_if));
ifp->info = drvr_priv;
drvr_priv->iflist[ifidx] = ifp;
- strlcpy(ifp->name, name, IFNAMSIZ);
if (mac_addr != NULL)
memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
- if (handle == NULL) {
+ if (ndev == NULL) {
ifp->state = BRCMF_E_IF_ADD;
ifp->idx = ifidx;
- up(&drvr_priv->sysioc_sem);
+ /*
+ * Delete the existing interface before overwriting it
+ * in case we missed the BRCMF_E_IF_DEL event.
+ */
+ if (ifp->ndev != NULL) {
+ brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
+ ifp->ndev->name);
+ netif_stop_queue(ifp->ndev);
+ unregister_netdev(ifp->ndev);
+ free_netdev(ifp->ndev);
+ }
+
+ /* Allocate netdev, including space for private structure */
+ ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d",
+ ether_setup);
+ if (!ifp->ndev) {
+ brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
+ ret = -ENOMEM;
+ }
+
+ if (ret == 0) {
+ memcpy(netdev_priv(ifp->ndev), &drvr_priv,
+ sizeof(drvr_priv));
+ err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
+ if (err != 0) {
+ brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n",
+ err);
+ ret = -EOPNOTSUPP;
+ } else {
+ brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
+ current->pid, ifp->ndev->name);
+ ifp->state = 0;
+ }
+ }
+
+ if (ret < 0) {
+ if (ifp->ndev)
+ free_netdev(ifp->ndev);
+
+ drvr_priv->iflist[ifp->idx] = NULL;
+ kfree(ifp);
+ }
} else
- ifp->net = (struct net_device *)handle;
+ ifp->ndev = ndev;
return 0;
}
@@ -1258,65 +970,55 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
{
struct brcmf_if *ifp;
- BRCMF_TRACE(("%s: idx %d\n", __func__, ifidx));
+ brcmf_dbg(TRACE, "idx %d\n", ifidx);
ifp = drvr_priv->iflist[ifidx];
if (!ifp) {
- BRCMF_ERROR(("%s: Null interface\n", __func__));
+ brcmf_dbg(ERROR, "Null interface\n");
return;
}
ifp->state = BRCMF_E_IF_DEL;
ifp->idx = ifidx;
- up(&drvr_priv->sysioc_sem);
+ if (ifp->ndev != NULL) {
+ netif_stop_queue(ifp->ndev);
+ unregister_netdev(ifp->ndev);
+ free_netdev(ifp->ndev);
+ drvr_priv->iflist[ifidx] = NULL;
+ kfree(ifp);
+ }
}
struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
{
struct brcmf_info *drvr_priv = NULL;
- struct net_device *net;
+ struct net_device *ndev;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- /* Allocate etherdev, including space for private structure */
- net = alloc_etherdev(sizeof(drvr_priv));
- if (!net) {
- BRCMF_ERROR(("%s: OOM - alloc_etherdev\n", __func__));
+ /* Allocate netdev, including space for private structure */
+ ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
+ if (!ndev) {
+ brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
goto fail;
}
/* Allocate primary brcmf_info */
drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
- if (!drvr_priv) {
- BRCMF_ERROR(("%s: OOM - alloc brcmf_info\n", __func__));
+ if (!drvr_priv)
goto fail;
- }
/*
* Save the brcmf_info into the priv
*/
- memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv));
-
- /* Set network interface name if it was provided as module parameter */
- if (iface_name[0]) {
- int len;
- char ch;
- strncpy(net->name, iface_name, IFNAMSIZ);
- net->name[IFNAMSIZ - 1] = 0;
- len = strlen(net->name);
- ch = net->name[len - 1];
- if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
- strcat(net->name, "%d");
- }
+ memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
- if (brcmf_add_if(drvr_priv, 0, (void *)net, net->name, NULL, 0, 0) ==
+ if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) ==
BRCMF_BAD_IF)
goto fail;
- net->netdev_ops = NULL;
- sema_init(&drvr_priv->proto_sem, 1);
- /* Initialize other structure content */
- init_waitqueue_head(&drvr_priv->ioctl_resp_wait);
+ ndev->netdev_ops = NULL;
+ mutex_init(&drvr_priv->proto_block);
/* Link to info module */
drvr_priv->pub.info = drvr_priv;
@@ -1327,41 +1029,33 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
/* Attach and link in the protocol */
if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
- BRCMF_ERROR(("brcmf_prot_attach failed\n"));
+ brcmf_dbg(ERROR, "brcmf_prot_attach failed\n");
goto fail;
}
/* Attach and link in the cfg80211 */
- if (unlikely(brcmf_cfg80211_attach(net, &drvr_priv->pub))) {
- BRCMF_ERROR(("wl_cfg80211_attach failed\n"));
+ drvr_priv->pub.config =
+ brcmf_cfg80211_attach(ndev,
+ brcmf_bus_get_device(bus),
+ &drvr_priv->pub);
+ if (drvr_priv->pub.config == NULL) {
+ brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
goto fail;
}
- if (brcmf_sysioc) {
- sema_init(&drvr_priv->sysioc_sem, 0);
- drvr_priv->sysioc_tsk = kthread_run(_brcmf_sysioc_thread, drvr_priv,
- "_brcmf_sysioc");
- if (IS_ERR(drvr_priv->sysioc_tsk)) {
- printk(KERN_WARNING
- "_brcmf_sysioc thread failed to start\n");
- drvr_priv->sysioc_tsk = NULL;
- }
- } else
- drvr_priv->sysioc_tsk = NULL;
+ INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
+ INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
/*
* Save the brcmf_info into the priv
*/
- memcpy(netdev_priv(net), &drvr_priv, sizeof(drvr_priv));
+ memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-#if defined(CONFIG_PM_SLEEP)
- atomic_set(&brcmf_mmc_suspend, false);
-#endif /* defined(CONFIG_PM_SLEEP) */
return &drvr_priv->pub;
fail:
- if (net)
- free_netdev(net);
+ if (ndev)
+ free_netdev(ndev);
if (drvr_priv)
brcmf_detach(&drvr_priv->pub);
@@ -1375,25 +1069,24 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
/* Room for "event_msgs" + '\0' + bitvec */
char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
- BRCMF_TRACE(("%s:\n", __func__));
+ brcmf_dbg(TRACE, "\n");
/* Bring up the bus */
- ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub, true);
+ ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub);
if (ret != 0) {
- BRCMF_ERROR(("%s, brcmf_sdbrcm_bus_init failed %d\n", __func__,
- ret));
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
return ret;
}
/* If bus is not ready, can't come up */
if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) {
- BRCMF_ERROR(("%s failed bus is not ready\n", __func__));
+ brcmf_dbg(ERROR, "failed bus is not ready\n");
return -ENODEV;
}
- brcmu_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
+ brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN,
iovbuf, sizeof(iovbuf));
- brcmf_proto_cdc_query_ioctl(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
+ brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf,
sizeof(iovbuf));
memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN);
@@ -1437,20 +1130,20 @@ static struct net_device_ops brcmf_netdev_ops_pri = {
.ndo_do_ioctl = brcmf_netdev_ioctl_entry,
.ndo_start_xmit = brcmf_netdev_start_xmit,
.ndo_set_mac_address = brcmf_netdev_set_mac_address,
- .ndo_set_multicast_list = brcmf_netdev_set_multicast_list
+ .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
};
int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
{
struct brcmf_info *drvr_priv = drvr->info;
- struct net_device *net;
+ struct net_device *ndev;
u8 temp_addr[ETH_ALEN] = {
0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
- BRCMF_TRACE(("%s: ifidx %d\n", __func__, ifidx));
+ brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
- net = drvr_priv->iflist[ifidx]->net;
- net->netdev_ops = &brcmf_netdev_ops_pri;
+ ndev = drvr_priv->iflist[ifidx]->ndev;
+ ndev->netdev_ops = &brcmf_netdev_ops_pri;
/*
* We have to use the primary MAC for virtual interfaces
@@ -1462,32 +1155,31 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
}
if (ifidx == 1) {
- BRCMF_TRACE(("%s ACCESS POINT MAC:\n", __func__));
+ brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
/* ACCESSPOINT INTERFACE CASE */
temp_addr[0] |= 0X02; /* set bit 2 ,
- Locally Administered address */
}
- net->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen;
- net->ethtool_ops = &brcmf_ethtool_ops;
+ ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen;
+ ndev->ethtool_ops = &brcmf_ethtool_ops;
- drvr_priv->pub.rxsz = net->mtu + net->hard_header_len +
- drvr_priv->pub.hdrlen;
+ drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len +
+ drvr_priv->pub.hdrlen;
- memcpy(net->dev_addr, temp_addr, ETH_ALEN);
+ memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
- if (register_netdev(net) != 0) {
- BRCMF_ERROR(("%s: couldn't register the net device\n",
- __func__));
+ if (register_netdev(ndev) != 0) {
+ brcmf_dbg(ERROR, "couldn't register the net device\n");
goto fail;
}
- BRCMF_INFO(("%s: Broadcom Dongle Host Driver\n", net->name));
+ brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
return 0;
fail:
- net->netdev_ops = NULL;
+ ndev->netdev_ops = NULL;
return -EBADE;
}
@@ -1495,7 +1187,7 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
{
struct brcmf_info *drvr_priv;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
if (drvr) {
drvr_priv = drvr->info;
@@ -1504,7 +1196,7 @@ static void brcmf_bus_detach(struct brcmf_pub *drvr)
brcmf_proto_stop(&drvr_priv->pub);
/* Stop the bus module */
- brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus, true);
+ brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus);
}
}
}
@@ -1513,7 +1205,7 @@ void brcmf_detach(struct brcmf_pub *drvr)
{
struct brcmf_info *drvr_priv;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
if (drvr) {
drvr_priv = drvr->info;
@@ -1526,25 +1218,24 @@ void brcmf_detach(struct brcmf_pub *drvr)
brcmf_del_if(drvr_priv, i);
ifp = drvr_priv->iflist[0];
- if (ifp->net->netdev_ops == &brcmf_netdev_ops_pri) {
- brcmf_netdev_stop(ifp->net);
- unregister_netdev(ifp->net);
+ if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+ rtnl_lock();
+ brcmf_netdev_stop(ifp->ndev);
+ rtnl_unlock();
+ unregister_netdev(ifp->ndev);
}
- if (drvr_priv->sysioc_tsk) {
- send_sig(SIGTERM, drvr_priv->sysioc_tsk, 1);
- kthread_stop(drvr_priv->sysioc_tsk);
- drvr_priv->sysioc_tsk = NULL;
- }
+ cancel_work_sync(&drvr_priv->setmacaddr_work);
+ cancel_work_sync(&drvr_priv->multicast_work);
brcmf_bus_detach(drvr);
if (drvr->prot)
brcmf_proto_detach(drvr);
- brcmf_cfg80211_detach();
+ brcmf_cfg80211_detach(drvr->config);
- free_netdev(ifp->net);
+ free_netdev(ifp->ndev);
kfree(ifp);
kfree(drvr_priv);
}
@@ -1553,7 +1244,7 @@ void brcmf_detach(struct brcmf_pub *drvr)
static void __exit brcmf_module_cleanup(void)
{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
brcmf_bus_unregister();
}
@@ -1562,12 +1253,12 @@ static int __init brcmf_module_init(void)
{
int error;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
error = brcmf_bus_register();
if (error) {
- BRCMF_ERROR(("%s: brcmf_bus_register failed\n", __func__));
+ brcmf_dbg(ERROR, "brcmf_bus_register failed\n");
goto failed;
}
return 0;
@@ -1584,7 +1275,7 @@ int brcmf_os_proto_block(struct brcmf_pub *drvr)
struct brcmf_info *drvr_priv = drvr->info;
if (drvr_priv) {
- down(&drvr_priv->proto_sem);
+ mutex_lock(&drvr_priv->proto_block);
return 1;
}
return 0;
@@ -1595,84 +1286,13 @@ int brcmf_os_proto_unblock(struct brcmf_pub *drvr)
struct brcmf_info *drvr_priv = drvr->info;
if (drvr_priv) {
- up(&drvr_priv->proto_sem);
+ mutex_unlock(&drvr_priv->proto_block);
return 1;
}
return 0;
}
-unsigned int brcmf_os_get_ioctl_resp_timeout(void)
-{
- return (unsigned int)brcmf_ioctl_timeout_msec;
-}
-
-void brcmf_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
-{
- brcmf_ioctl_timeout_msec = (int)timeout_msec;
-}
-
-int brcmf_os_ioctl_resp_wait(struct brcmf_pub *drvr, uint *condition,
- bool *pending)
-{
- struct brcmf_info *drvr_priv = drvr->info;
- DECLARE_WAITQUEUE(wait, current);
- int timeout = brcmf_ioctl_timeout_msec;
-
- /* Convert timeout in millsecond to jiffies */
- timeout = timeout * HZ / 1000;
-
- /* Wait until control frame is available */
- add_wait_queue(&drvr_priv->ioctl_resp_wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- while (!(*condition) && (!signal_pending(current) && timeout))
- timeout = schedule_timeout(timeout);
-
- if (signal_pending(current))
- *pending = true;
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&drvr_priv->ioctl_resp_wait, &wait);
-
- return timeout;
-}
-
-int brcmf_os_ioctl_resp_wake(struct brcmf_pub *drvr)
-{
- struct brcmf_info *drvr_priv = drvr->info;
-
- if (waitqueue_active(&drvr_priv->ioctl_resp_wait))
- wake_up_interruptible(&drvr_priv->ioctl_resp_wait);
-
- return 0;
-}
-
-static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
- struct brcmf_event_msg *event, void **data)
-{
- int bcmerror = 0;
-
- bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data);
- if (bcmerror != 0)
- return bcmerror;
-
- if (drvr_priv->iflist[*ifidx]->net)
- brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->net,
- event, *data);
-
- return bcmerror;
-}
-
-int brcmf_netdev_reset(struct net_device *dev, u8 flag)
-{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(dev);
-
- brcmf_bus_devreset(&drvr_priv->pub, flag);
-
- return 1;
-}
-
static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
{
return atomic_read(&drvr_priv->pend_8021x_cnt);
@@ -1680,9 +1300,9 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
#define MAX_WAIT_FOR_8021X_TX 10
-int brcmf_netdev_wait_pend8021x(struct net_device *dev)
+int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
{
- struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(dev);
+ struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev);
int timeout = 10 * HZ / 1000;
int ntimes = MAX_WAIT_FOR_8021X_TX;
int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
@@ -1700,7 +1320,7 @@ int brcmf_netdev_wait_pend8021x(struct net_device *dev)
}
#ifdef BCMDBG
-int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size)
+int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size)
{
int ret = 0;
struct file *fp;
@@ -1714,13 +1334,13 @@ int brcmf_write_to_file(struct brcmf_pub *drvr, u8 *buf, int size)
/* open file to write */
fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640);
if (!fp) {
- BRCMF_ERROR(("%s: open file error\n", __func__));
+ brcmf_dbg(ERROR, "open file error\n");
ret = -1;
goto exit;
}
/* Write buf to file */
- fp->f_op->write(fp, buf, size, &pos);
+ fp->f_op->write(fp, (char __user *)buf, size, &pos);
exit:
/* free buf before return */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h
index ff788b37afdc..4ee1ea846f6d 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_proto.h
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_proto.h
@@ -17,14 +17,6 @@
#ifndef _BRCMF_PROTO_H_
#define _BRCMF_PROTO_H_
-#ifndef IOCTL_RESP_TIMEOUT
-#define IOCTL_RESP_TIMEOUT 2000 /* In milli second */
-#endif
-
-#ifndef IOCTL_CHIP_ACTIVE_TIMEOUT
-#define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */
-#endif
-
/*
* Exported from the brcmf protocol module (brcmf_cdc)
*/
@@ -53,23 +45,16 @@ extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
extern int brcmf_proto_hdrpull(struct brcmf_pub *, int *ifidx,
struct sk_buff *rxp);
-/* Use protocol to issue ioctl to dongle */
-extern int brcmf_proto_ioctl(struct brcmf_pub *drvr, int ifidx,
- struct brcmf_ioctl *ioc, void *buf, int len);
-
-/* Add prot dump output to a buffer */
-extern void brcmf_proto_dump(struct brcmf_pub *drvr,
- struct brcmu_strbuf *strbuf);
+/* Use protocol to issue command to dongle */
+extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx,
+ struct brcmf_dcmd *dcmd, int len);
/* Update local copy of dongle statistics */
extern void brcmf_proto_dstats(struct brcmf_pub *drvr);
-extern int brcmf_c_ioctl(struct brcmf_pub *drvr, struct brcmf_c_ioctl *ioc,
- void *buf, uint buflen);
-
-extern int brcmf_c_preinit_ioctls(struct brcmf_pub *drvr);
+extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr);
-extern int brcmf_proto_cdc_set_ioctl(struct brcmf_pub *drvr, int ifidx,
+extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx,
uint cmd, void *buf, uint len);
#endif /* _BRCMF_PROTO_H_ */
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index 7fa95b6213c5..b716e3124330 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -24,8 +24,10 @@
#include <linux/sched.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
#include <linux/semaphore.h>
#include <linux/firmware.h>
+#include <linux/module.h>
#include <asm/unaligned.h>
#include <defs.h>
#include <brcmu_wifi.h>
@@ -34,85 +36,18 @@
#include <soc.h>
#include "sdio_host.h"
-/* register access macros */
-#ifndef __BIG_ENDIAN
-#ifndef __mips__
-#define R_REG(r, typ) \
- brcmf_sdcard_reg_read(NULL, (r), sizeof(typ))
-#else /* __mips__ */
-#define R_REG(r, typ) \
- ({ \
- __typeof(*(r)) __osl_v; \
- __asm__ __volatile__("sync"); \
- __osl_v = brcmf_sdcard_reg_read(NULL, (r),\
- sizeof(typ)); \
- __asm__ __volatile__("sync"); \
- __osl_v; \
- })
-#endif /* __mips__ */
-
-#else /* __BIG_ENDIAN */
-#define R_REG(r, typ) \
- brcmf_sdcard_reg_read(NULL, (r), sizeof(typ))
-#endif /* __BIG_ENDIAN */
-
-#define OR_REG(r, v, typ) \
- brcmf_sdcard_reg_write(NULL, (r), sizeof(typ), R_REG(r, typ) | (v))
+#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
#ifdef BCMDBG
-/* ARM trap handling */
-
-/* Trap types defined by ARM (see arminc.h) */
-
-#if defined(__ARM_ARCH_4T__)
-#define MAX_TRAP_TYPE (TR_FIQ + 1)
-#elif defined(__ARM_ARCH_7M__)
-#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
-#endif /* __ARM_ARCH_7M__ */
-
-/* The trap structure is defined here as offsets for assembly */
-#define TR_TYPE 0x00
-#define TR_EPC 0x04
-#define TR_CPSR 0x08
-#define TR_SPSR 0x0c
-#define TR_REGS 0x10
-#define TR_REG(n) (TR_REGS + (n) * 4)
-#define TR_SP TR_REG(13)
-#define TR_LR TR_REG(14)
-#define TR_PC TR_REG(15)
-
-#define TRAP_T_SIZE 80
-
-struct brcmf_trap {
- u32 type;
- u32 epc;
- u32 cpsr;
- u32 spsr;
- u32 r0;
- u32 r1;
- u32 r2;
- u32 r3;
- u32 r4;
- u32 r5;
- u32 r6;
- u32 r7;
- u32 r8;
- u32 r9;
- u32 r10;
- u32 r11;
- u32 r12;
- u32 r13;
- u32 r14;
- u32 pc;
-};
+#define BRCMF_TRAP_INFO_SIZE 80
#define CBUF_LEN (128)
-struct rte_log {
- u32 buf; /* Can't be pointer on (64-bit) hosts */
- uint buf_size;
- uint idx;
+struct rte_log_le {
+ __le32 buf; /* Can't be pointer on (64-bit) hosts */
+ __le32 buf_size;
+ __le32 idx;
char *_buf_compat; /* Redundant pointer for backward compat. */
};
@@ -126,8 +61,8 @@ struct rte_console {
* (at risk of conflicting with
* the real UART). vcons_out is currently unused.
*/
- volatile uint vcons_in;
- volatile uint vcons_out;
+ uint vcons_in;
+ uint vcons_out;
/* Output (logging) buffer
* Console output is written to a ring buffer log_buf at index log_idx.
@@ -135,7 +70,7 @@ struct rte_console {
* Output will be lost if the output wraps around faster than the host
* polls.
*/
- struct rte_log log;
+ struct rte_log_le log_le;
/* Console input line buffer
* Characters are read one at a time into cbuf
@@ -176,57 +111,67 @@ struct rte_console {
#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold
biggest possible glom */
-#ifndef BRCMF_FIRSTREAD
-#define BRCMF_FIRSTREAD 32
-#endif
+#define BRCMF_FIRSTREAD (1 << 6)
-#if !ISPOWEROF2(BRCMF_FIRSTREAD)
-#error BRCMF_FIRSTREAD is not a power of 2!
-#endif
/* SBSDIO_DEVICE_CTL */
-#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when
- * receiving CMD53
- */
-#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is
- * synchronous to the sdio clock
- */
-#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host
- * except the chipActive (rev 8)
- */
-#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put
- * external pads in tri-state; requires
- * sdio bus power cycle to clear (rev 9)
- */
-#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */
-#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */
-#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */
-#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */
+
+/* 1: device will assert busy signal when receiving CMD53 */
+#define SBSDIO_DEVCTL_SETBUSY 0x01
+/* 1: assertion of sdio interrupt is synchronous to the sdio clock */
+#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02
+/* 1: mask all interrupts to host except the chipActive (rev 8) */
+#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04
+/* 1: isolate internal sdio signals, put external pads in tri-state; requires
+ * sdio bus power cycle to clear (rev 9) */
+#define SBSDIO_DEVCTL_PADS_ISO 0x08
+/* Force SD->SB reset mapping (rev 11) */
+#define SBSDIO_DEVCTL_SB_RST_CTL 0x30
+/* Determined by CoreControl bit */
+#define SBSDIO_DEVCTL_RST_CORECTL 0x00
+/* Force backplane reset */
+#define SBSDIO_DEVCTL_RST_BPRESET 0x10
+/* Force no backplane reset */
+#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20
/* SBSDIO_FUNC1_CHIPCLKCSR */
-#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */
-#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */
-#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */
-#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */
-#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */
-#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */
-#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */
-#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */
-
-#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
-#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
-#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
-#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
-#define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \
- (alponly ? 1 : SBSDIO_HTAV(regval)))
+
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP 0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT 0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP 0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ 0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ 0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL 0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL 0x80
+
+#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+
+#define SBSDIO_CLKAV(regval, alponly) \
+ (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
/* direct(mapped) cis space */
-#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */
-#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */
-#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */
-#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple,
- * link bytes
- */
+/* MAPPED common CIS address */
+#define SBSDIO_CIS_BASE_COMMON 0x1000
+/* maximum bytes in one CIS */
+#define SBSDIO_CIS_SIZE_LIMIT 0x200
+/* cis offset addr is < 17 bits */
+#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF
+
+/* manfid tuple length, include tuple, link bytes */
+#define SBSDIO_CIS_MANFID_TUPLE_LEN 6
/* intstatus */
#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
@@ -282,11 +227,7 @@ struct rte_console {
/* Total length of frame header for dongle protocol */
#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
-#ifdef SDTEST
-#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + BRCMF_SDALIGN)
-#else
#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN)
-#endif
/*
* Software allocation of To SB Mailbox resources
@@ -362,29 +303,6 @@ struct rte_console {
#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80)
-/* For TEST_CHANNEL packets, define another 4-byte header */
-#define SDPCM_TEST_HDRLEN 4 /*
- * Generally: Cmd(1), Ext(1), Len(2);
- * Semantics of Ext byte depend on
- * command. Len is current or requested
- * frame length, not including test
- * header; sent little-endian.
- */
-#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext:pattern id. */
-#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext:pattern id. */
-#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext:pattern id. */
-#define SDPCM_TEST_BURST 0x04 /*
- * Receiver to send a burst.
- * Ext is a frame count
- */
-#define SDPCM_TEST_SEND 0x05 /*
- * Receiver sets send mode.
- * Ext is boolean on/off
- */
-
-/* Handy macro for filling in datagen packets with a pattern */
-#define SDPCM_TEST_FILL(byteno, id) ((u8)(id + byteno))
-
/*
* Shared structure between dongle and the host.
* The structure contains pointers to trap or assert information.
@@ -395,15 +313,8 @@ struct rte_console {
#define SDPCM_SHARED_ASSERT 0x0200
#define SDPCM_SHARED_TRAP 0x0400
-
/* Space for header read, limit for data packets */
-#ifndef MAX_HDR_READ
-#define MAX_HDR_READ 32
-#endif
-#if !ISPOWEROF2(MAX_HDR_READ)
-#error MAX_HDR_READ is not a power of 2!
-#endif
-
+#define MAX_HDR_READ (1 << 6)
#define MAX_RX_DATASZ 2048
/* Maximum milliseconds to wait for F2 to come up */
@@ -414,10 +325,8 @@ struct rte_console {
* for HT availability, it could take a couple hundred ms more, so
* max out at a 1 second (1000000us).
*/
-#if (PMU_MAX_TRANSITION_DLY <= 1000000)
#undef PMU_MAX_TRANSITION_DLY
#define PMU_MAX_TRANSITION_DLY 1000000
-#endif
/* Value for ChipClockCSR during initial setup */
#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \
@@ -433,12 +342,18 @@ struct rte_console {
#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
/* sbtmstatelow */
-#define SBTML_RESET 0x0001 /* reset */
-#define SBTML_REJ_MASK 0x0006 /* reject field */
-#define SBTML_REJ 0x0002 /* reject */
-#define SBTML_TMPREJ 0x0004 /* temporary reject, for error recovery */
-#define SBTML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */
+/* reset */
+#define SBTML_RESET 0x0001
+/* reject field */
+#define SBTML_REJ_MASK 0x0006
+/* reject */
+#define SBTML_REJ 0x0002
+/* temporary reject, for error recovery */
+#define SBTML_TMPREJ 0x0004
+
+/* Shift to locate the SI control flags in sbtml */
+#define SBTML_SICF_SHIFT 16
/* sbtmstatehigh */
#define SBTMH_SERR 0x0001 /* serror */
@@ -446,7 +361,8 @@ struct rte_console {
#define SBTMH_BUSY 0x0004 /* busy */
#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */
-#define SBTMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */
+/* Shift to locate the SI status flags in sbtmh */
+#define SBTMH_SISF_SHIFT 16
/* sbidlow */
#define SBIDL_INIT 0x80 /* initiator */
@@ -456,7 +372,8 @@ struct rte_console {
#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
#define SBIDH_RCE_SHIFT 8
#define SBCOREREV(sbidh) \
- ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK))
+ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \
+ ((sbidh) & SBIDH_RC_MASK))
#define SBIDH_CC_MASK 0x8ff0 /* core code */
#define SBIDH_CC_SHIFT 4
#define SBIDH_VC_MASK 0xffff0000 /* vendor code */
@@ -465,17 +382,18 @@ struct rte_console {
/*
* Conversion of 802.1D priority to precedence level
*/
-#define PRIO2PREC(prio) \
- (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? \
- ((prio^2)) : (prio))
-
-BRCMF_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
+static uint prio2prec(u32 prio)
+{
+ return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ?
+ (prio^2) : prio;
+}
/*
* Core reg address translation.
* Both macro's returns a 32 bits byte address on the backplane bus.
*/
-#define CORE_CC_REG(base, field) (base + offsetof(chipcregs_t, field))
+#define CORE_CC_REG(base, field) \
+ (base + offsetof(struct chipcregs, field))
#define CORE_BUS_REG(base, field) \
(base + offsetof(struct sdpcmd_regs, field))
#define CORE_SB(base, field) \
@@ -575,7 +493,7 @@ struct sdpcmd_regs {
struct brcmf_console {
uint count; /* Poll interval msec counter */
uint log_addr; /* Log struct address (fixed) */
- struct rte_log log; /* Log struct (host copy) */
+ struct rte_log_le log_le; /* Log struct (host copy) */
uint bufsize; /* Size of log buffer */
u8 *buf; /* Log buffer (host copy) */
uint last; /* Last buffer read index */
@@ -593,6 +511,17 @@ struct sdpcm_shared {
u8 tag[32];
};
+struct sdpcm_shared_le {
+ __le32 flags;
+ __le32 trap_addr;
+ __le32 assert_exp_addr;
+ __le32 assert_file_addr;
+ __le32 assert_line;
+ __le32 console_addr; /* Address of struct rte_console */
+ __le32 msgtrace_addr;
+ u8 tag[32];
+};
+
/* misc chip info needed by some of the routines */
struct chip_info {
@@ -614,22 +543,18 @@ struct chip_info {
struct brcmf_bus {
struct brcmf_pub *drvr;
- struct brcmf_sdio_card *card; /* Handle for sdio card calls */
+ struct brcmf_sdio_dev *sdiodev; /* sdio device handler */
struct chip_info *ci; /* Chip info struct */
char *vars; /* Variables (from CIS and/or other) */
uint varsz; /* Size of variables buffer */
u32 ramsize; /* Size of RAM in SOCRAM (bytes) */
- u32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
- u32 bus; /* gSPI or SDIO bus */
u32 hostintmask; /* Copy of Host Interrupt Mask */
u32 intstatus; /* Intstatus bits (events) pending */
bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
bool fcstate; /* State of dongle flow-control */
- u16 cl_devid; /* cached devid for brcmf_sdio_probe_attach() */
-
uint blocksize; /* Block size of SDIO transfers */
uint roundup; /* Max roundup limit */
@@ -644,6 +569,10 @@ struct brcmf_bus {
u8 rx_seq; /* Receive sequence number (expected) */
bool rxskip; /* Skip receive (awaiting NAK ACK) */
+ uint rxbound; /* Rx frames to read before resched */
+ uint txbound; /* Tx frames to send before resched */
+ uint txminmax;
+
struct sk_buff *glomd; /* Packet containing glomming descriptor */
struct sk_buff *glom; /* Packet chain for glommed superframe */
uint glomerr; /* Glom packet read errors */
@@ -660,7 +589,6 @@ struct brcmf_bus {
bool intr; /* Use interrupts */
bool poll; /* Use polling */
bool ipend; /* Device interrupt is pending */
- bool intdis; /* Interrupts disabled by isr */
uint intrcount; /* Count of device interrupt callbacks */
uint lastintrs; /* Count as of last watchdog timer */
uint spurious; /* Count of spurious interrupts */
@@ -669,6 +597,7 @@ struct brcmf_bus {
uint pollcnt; /* Count of active polls */
#ifdef BCMDBG
+ uint console_interval;
struct brcmf_console console; /* Console output polling support */
uint console_addr; /* Console address from shared struct */
#endif /* BCMDBG */
@@ -689,30 +618,6 @@ struct brcmf_bus {
/* Field to decide if rx of control frames happen in rxbuf or lb-pool */
bool usebufpool;
-#ifdef SDTEST
- /* external loopback */
- bool ext_loop;
- u8 loopid;
-
- /* pktgen configuration */
- uint pktgen_freq; /* Ticks between bursts */
- uint pktgen_count; /* Packets to send each burst */
- uint pktgen_print; /* Bursts between count displays */
- uint pktgen_total; /* Stop after this many */
- uint pktgen_minlen; /* Minimum packet data len */
- uint pktgen_maxlen; /* Maximum packet data len */
- uint pktgen_mode; /* Configured mode: tx, rx, or echo */
- uint pktgen_stop; /* Number of tx failures causing stop */
-
- /* active pktgen fields */
- uint pktgen_tick; /* Tick counter for bursts */
- uint pktgen_ptick; /* Burst counter for printing */
- uint pktgen_sent; /* Number of test packets generated */
- uint pktgen_rcvd; /* Number of test packets received */
- uint pktgen_fail; /* Number of failed send attempts */
- u16 pktgen_len; /* Length of next packet to send */
-#endif /* SDTEST */
-
/* Some additional counters */
uint tx_sderrs; /* Count of tx attempts with sd errors */
uint fcqueued; /* Tx packets that got queued */
@@ -739,19 +644,18 @@ struct brcmf_bus {
spinlock_t txqlock;
wait_queue_head_t ctrl_wait;
+ wait_queue_head_t dcmd_resp_wait;
struct timer_list timer;
struct completion watchdog_wait;
struct task_struct *watchdog_tsk;
bool wd_timer_valid;
+ uint save_ms;
- struct tasklet_struct tasklet;
struct task_struct *dpc_tsk;
struct completion dpc_wait;
- bool threads_only;
struct semaphore sdsem;
- spinlock_t sdlock;
const char *fw_name;
const struct firmware *firmware;
@@ -805,82 +709,39 @@ struct sbconfig {
#define CLK_PENDING 2 /* Not used yet */
#define CLK_AVAIL 3
-#define BRCMF_NOPMU(brcmf) (false)
-
#ifdef BCMDBG
static int qcount[NUMPRIO];
static int tx_packets[NUMPRIO];
#endif /* BCMDBG */
-/* Deferred transmit */
-uint brcmf_deferred_tx = 1;
-module_param(brcmf_deferred_tx, uint, 0);
+#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */
-/* Watchdog thread priority, -1 to use kernel timer */
-int brcmf_watchdog_prio = 97;
-module_param(brcmf_watchdog_prio, int, 0);
-
-/* Watchdog interval */
-uint brcmf_watchdog_ms = 10;
-module_param(brcmf_watchdog_ms, uint, 0);
-
-/* DPC thread priority, -1 to use tasklet */
-int brcmf_dpc_prio = 98;
-module_param(brcmf_dpc_prio, int, 0);
-
-#ifdef BCMDBG
-/* Console poll interval */
-uint brcmf_console_ms;
-module_param(brcmf_console_ms, uint, 0);
-#endif /* BCMDBG */
-
-/* Tx/Rx bounds */
-uint brcmf_txbound;
-uint brcmf_rxbound;
-uint brcmf_txminmax;
-
-/* override the RAM size if possible */
-#define DONGLE_MIN_MEMSIZE (128 * 1024)
-int brcmf_dongle_memsize;
-
-static bool brcmf_alignctl;
-
-static bool sd1idle;
-
-static bool retrydata;
-#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
-
-static const uint watermark = 8;
-static const uint firstread = BRCMF_FIRSTREAD;
+#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL)
/* Retry count for register access failures */
static const uint retry_limit = 2;
-/* Force even SD lengths (some host controllers mess up on odd bytes) */
-static bool forcealign;
-
-#define ALIGNMENT 4
-
-#define PKTALIGN(_p, _len, _align) \
- do { \
- uint datalign; \
- datalign = (unsigned long)((_p)->data); \
- datalign = roundup(datalign, (_align)) - datalign; \
- if (datalign) \
- skb_pull((_p), datalign); \
- __skb_trim((_p), (_len)); \
- } while (0)
-
/* Limit on rounding up frames */
static const uint max_roundup = 512;
-/* Try doing readahead */
-static bool brcmf_readahead;
+#define ALIGNMENT 4
+
+static void pkt_align(struct sk_buff *p, int len, int align)
+{
+ uint datalign;
+ datalign = (unsigned long)(p->data);
+ datalign = roundup(datalign, (align)) - datalign;
+ if (datalign)
+ skb_pull(p, datalign);
+ __skb_trim(p, len);
+}
/* To check if there's window offered */
-#define DATAOK(bus) \
- (((u8)(bus->tx_max - bus->tx_seq) != 0) && \
- (((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
+static bool data_ok(struct brcmf_bus *bus)
+{
+ return (u8)(bus->tx_max - bus->tx_seq) != 0 &&
+ ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0;
+}
/*
* Reads a register in the SDIO hardware block. This block occupies a series of
@@ -891,13 +752,14 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
{
*retryvar = 0;
do {
- *regvar = R_REG(bus->ci->buscorebase + reg_offset, u32);
- } while (brcmf_sdcard_regfail(bus->card) &&
+ *regvar = brcmf_sdcard_reg_read(bus->sdiodev,
+ bus->ci->buscorebase + reg_offset, sizeof(u32));
+ } while (brcmf_sdcard_regfail(bus->sdiodev) &&
(++(*retryvar) <= retry_limit));
if (*retryvar) {
bus->regfails += (*retryvar-1);
if (*retryvar > retry_limit) {
- BRCMF_ERROR(("FAILED READ %Xh\n", reg_offset));
+ brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset);
*regvar = 0;
}
}
@@ -908,133 +770,42 @@ w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
{
*retryvar = 0;
do {
- brcmf_sdcard_reg_write(NULL, bus->ci->buscorebase + reg_offset,
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ bus->ci->buscorebase + reg_offset,
sizeof(u32), regval);
- } while (brcmf_sdcard_regfail(bus->card) &&
+ } while (brcmf_sdcard_regfail(bus->sdiodev) &&
(++(*retryvar) <= retry_limit));
if (*retryvar) {
bus->regfails += (*retryvar-1);
if (*retryvar > retry_limit)
- BRCMF_ERROR(("FAILED REGISTER WRITE"
- " %Xh\n", reg_offset));
+ brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n",
+ reg_offset);
}
}
-#define BRCMF_BUS SDIO_BUS
-
#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
-#ifdef SDTEST
-static void brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, void *pkt, uint seq);
-static void brcmf_sdbrcm_sdtest_set(struct brcmf_bus *bus, bool start);
-#endif
-
-#ifdef BCMDBG
-static int brcmf_sdbrcm_bus_console_in(struct brcmf_pub *drvr,
- unsigned char *msg, uint msglen);
-static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size);
-static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus);
-#endif /* BCMDBG */
-static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter);
-
-static void brcmf_sdbrcm_release(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_disconnect(void *ptr);
-static bool brcmf_sdbrcm_chipmatch(u16 chipid);
-static bool brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, void *card,
- u32 regsva, u16 devid);
-static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus, void *card);
-static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus, void *card);
-static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus);
-
-static uint brcmf_process_nvram_vars(char *varbuf, uint len);
-
-static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size);
-static int brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes,
- struct sk_buff *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle);
-
-static bool brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus, void *card);
-static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus);
-
-static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus);
-static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus);
-
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_card *card, u32 corebase);
-
-static int brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs);
-
-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_card *card, u32 corebase);
-
-static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
- u32 drivestrength);
-static void brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar);
-static void brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_watchdog(unsigned long data);
-static int brcmf_sdbrcm_watchdog_thread(void *data);
-static int brcmf_sdbrcm_dpc_thread(void *data);
-static void brcmf_sdbrcm_dpc_tasklet(unsigned long data);
-static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus);
-static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus);
-static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus);
-
/* Packet free applicable unconditionally for sdio and sdspi.
* Conditional if bufpool was present for gspi bus.
*/
static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt)
{
- if ((bus->bus != SPI_BUS) || bus->usebufpool)
+ if (bus->usebufpool)
brcmu_pkt_buf_free_skb(pkt);
}
-static void brcmf_sdbrcm_setmemsize(struct brcmf_bus *bus, int mem_size)
-{
- s32 min_size = DONGLE_MIN_MEMSIZE;
- /* Restrict the memsize to user specified limit */
- BRCMF_ERROR(("user: Restrict the dongle ram size to %d, min %d\n",
- brcmf_dongle_memsize, min_size));
- if ((brcmf_dongle_memsize > min_size) &&
- (brcmf_dongle_memsize < (s32) bus->orig_ramsize))
- bus->ramsize = brcmf_dongle_memsize;
-}
-
-static int brcmf_sdbrcm_set_siaddr_window(struct brcmf_bus *bus, u32 address)
-{
- int err = 0;
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
- (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
- if (!err)
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_SBADDRMID,
- (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
- if (!err)
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_SBADDRHIGH,
- (address >> 24) & SBSDIO_SBADDRHIGH_MASK,
- &err);
- return err;
-}
-
/* Turn backplane clock on or off */
static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
{
int err;
u8 clkctl, clkreq, devctl;
- struct brcmf_sdio_card *card;
+ unsigned long timeout;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
clkctl = 0;
- card = bus->card;
if (on) {
/* Request HT Avail */
@@ -1045,11 +816,10 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
&& (bus->ci->chiprev == 0))
clkreq |= SBSDIO_FORCE_ALP;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
if (err) {
- BRCMF_ERROR(("%s: HT Avail request error: %d\n",
- __func__, err));
+ brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
return -EBADE;
}
@@ -1062,74 +832,73 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
}
/* Check current status */
- clkctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
- BRCMF_ERROR(("%s: HT Avail read error: %d\n",
- __func__, err));
+ brcmf_dbg(ERROR, "HT Avail read error: %d\n", err);
return -EBADE;
}
/* Go to pending and await interrupt if appropriate */
if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
/* Allow only clock-available interrupt */
- devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
if (err) {
- BRCMF_ERROR(("%s: Devctl error setting CA:"
- " %d\n", __func__, err));
+ brcmf_dbg(ERROR, "Devctl error setting CA: %d\n",
+ err);
return -EBADE;
}
devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
- BRCMF_INFO(("CLKCTL: set PENDING\n"));
+ brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
bus->clkstate = CLK_PENDING;
return 0;
} else if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
devctl =
- brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
}
/* Otherwise, wait here (polling) for HT Avail */
- if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- BRCMF_SPINWAIT_SLEEP(sdioh_spinwait_sleep,
- ((clkctl =
- brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- &err)),
- !SBSDIO_CLKAV(clkctl, bus->alp_only)),
- PMU_MAX_TRANSITION_DLY);
+ timeout = jiffies +
+ msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
+ while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
+ if (time_after(jiffies, timeout))
+ break;
+ else
+ usleep_range(5000, 10000);
}
if (err) {
- BRCMF_ERROR(("%s: HT Avail request error: %d\n",
- __func__, err));
+ brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
return -EBADE;
}
if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- BRCMF_ERROR(("%s: HT Avail timeout (%d): "
- "clkctl 0x%02x\n", __func__,
- PMU_MAX_TRANSITION_DLY, clkctl));
+ brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n",
+ PMU_MAX_TRANSITION_DLY, clkctl);
return -EBADE;
}
/* Mark clock available */
bus->clkstate = CLK_AVAIL;
- BRCMF_INFO(("CLKCTL: turned ON\n"));
+ brcmf_dbg(INFO, "CLKCTL: turned ON\n");
#if defined(BCMDBG)
if (bus->alp_only != true) {
- if (SBSDIO_ALPONLY(clkctl)) {
- BRCMF_ERROR(("%s: HT Clock should be on.\n",
- __func__));
- }
+ if (SBSDIO_ALPONLY(clkctl))
+ brcmf_dbg(ERROR, "HT Clock should be on\n");
}
#endif /* defined (BCMDBG) */
@@ -1139,20 +908,21 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
- devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
}
bus->clkstate = CLK_SDONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
- BRCMF_INFO(("CLKCTL: turned OFF\n"));
+ brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
if (err) {
- BRCMF_ERROR(("%s: Failed access turning clock off:"
- " %d\n", __func__, err));
+ brcmf_dbg(ERROR, "Failed access turning clock off: %d\n",
+ err);
return -EBADE;
}
}
@@ -1162,7 +932,7 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
/* Change idle/active SD state */
static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on)
{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
if (on)
bus->clkstate = CLK_SDONLY;
@@ -1179,12 +949,12 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
uint oldstate = bus->clkstate;
#endif /* BCMDBG */
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* Early exit if we're already there */
if (bus->clkstate == target) {
if (target == CLK_AVAIL) {
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
bus->activity = true;
}
return 0;
@@ -1197,7 +967,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
brcmf_sdbrcm_sdclk(bus, true);
/* Now request HT Avail on the backplane */
brcmf_sdbrcm_htclk(bus, true, pendok);
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
bus->activity = true;
break;
@@ -1208,9 +978,9 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
else if (bus->clkstate == CLK_AVAIL)
brcmf_sdbrcm_htclk(bus, false, false);
else
- BRCMF_ERROR(("brcmf_sdbrcm_clkctl: request for %d -> %d"
- "\n", bus->clkstate, target));
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+ brcmf_dbg(ERROR, "request for %d -> %d\n",
+ bus->clkstate, target);
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
break;
case CLK_NONE:
@@ -1223,21 +993,19 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok)
break;
}
#ifdef BCMDBG
- BRCMF_INFO(("brcmf_sdbrcm_clkctl: %d -> %d\n",
- oldstate, bus->clkstate));
+ brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate);
#endif /* BCMDBG */
return 0;
}
-int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
+static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
{
- struct brcmf_sdio_card *card = bus->card;
uint retries = 0;
- BRCMF_INFO(("brcmf_sdbrcm_bussleep: request %s (currently %s)\n",
- (sleep ? "SLEEP" : "WAKE"),
- (bus->sleeping ? "SLEEP" : "WAKE")));
+ brcmf_dbg(INFO, "request %s (currently %s)\n",
+ sleep ? "SLEEP" : "WAKE",
+ bus->sleeping ? "SLEEP" : "WAKE");
/* Done if we're already in the requested state */
if (sleep == bus->sleeping)
@@ -1249,9 +1017,6 @@ int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
return -EBUSY;
- /* Disable SDIO interrupts (no longer interested) */
- brcmf_sdcard_intr_disable(bus->card);
-
/* Make sure the controller has the bus up */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
@@ -1259,20 +1024,18 @@ int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
w_sdreg32(bus, SMB_USE_OOB,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
if (retries > retry_limit)
- BRCMF_ERROR(("CANNOT SIGNAL CHIP, "
- "WILL NOT WAKE UP!!\n"));
+ brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n");
/* Turn off our contribution to the HT clock request */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
/* Isolate the bus */
- if (bus->ci->chip != BCM4329_CHIP_ID
- && bus->ci->chip != BCM4319_CHIP_ID) {
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ if (bus->ci->chip != BCM4329_CHIP_ID) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL,
SBSDIO_DEVCTL_PADS_ISO, NULL);
}
@@ -1283,14 +1046,14 @@ int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
} else {
/* Waking up: bus power up is ok, set local state */
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
/* Force pad isolation off if possible
(in case power never toggled) */
if ((bus->ci->buscoretype == PCMCIA_CORE_ID)
&& (bus->ci->buscorerev >= 10))
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, 0, NULL);
/* Make sure the controller has the bus up */
@@ -1305,2142 +1068,124 @@ int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
&retries);
if (retries > retry_limit)
- BRCMF_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
+ brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n");
/* Make sure we have SD bus access */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
/* Change state */
bus->sleeping = false;
-
- /* Enable interrupts again */
- if (bus->intr && (bus->drvr->busstate == BRCMF_BUS_DATA)) {
- bus->intdis = false;
- brcmf_sdcard_intr_enable(bus->card);
- }
}
return 0;
}
-#define BUS_WAKE(bus) \
- do { \
- if ((bus)->sleeping) \
- brcmf_sdbrcm_bussleep((bus), false); \
- } while (0);
-
-/* Writes a HW/SW header into the packet and sends it. */
-/* Assumes: (a) header space already there, (b) caller holds lock */
-static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, uint chan,
- bool free_pkt)
+static void bus_wake(struct brcmf_bus *bus)
{
- int ret;
- u8 *frame;
- u16 len, pad = 0;
- u32 swheader;
- uint retries = 0;
- struct brcmf_sdio_card *card;
- struct sk_buff *new;
- int i;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- card = bus->card;
-
- if (bus->drvr->dongle_reset) {
- ret = -EPERM;
- goto done;
- }
-
- frame = (u8 *) (pkt->data);
-
- /* Add alignment padding, allocate new packet if needed */
- pad = ((unsigned long)frame % BRCMF_SDALIGN);
- if (pad) {
- if (skb_headroom(pkt) < pad) {
- BRCMF_INFO(("%s: insufficient headroom %d for %d pad\n",
- __func__, skb_headroom(pkt), pad));
- bus->drvr->tx_realloc++;
- new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
- if (!new) {
- BRCMF_ERROR(("%s: couldn't allocate new "
- "%d-byte packet\n", __func__,
- pkt->len + BRCMF_SDALIGN));
- ret = -ENOMEM;
- goto done;
- }
-
- PKTALIGN(new, pkt->len, BRCMF_SDALIGN);
- memcpy(new->data, pkt->data, pkt->len);
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
- /* free the pkt if canned one is not used */
- free_pkt = true;
- pkt = new;
- frame = (u8 *) (pkt->data);
- /* precondition: (frame % BRCMF_SDALIGN) == 0) */
- pad = 0;
- } else {
- skb_push(pkt, pad);
- frame = (u8 *) (pkt->data);
- /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
- memset(frame, 0, pad + SDPCM_HDRLEN);
- }
- }
- /* precondition: pad < BRCMF_SDALIGN */
-
- /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- len = (u16) (pkt->len);
- *(u16 *) frame = cpu_to_le16(len);
- *(((u16 *) frame) + 1) = cpu_to_le16(~len);
-
- /* Software tag: channel, sequence number, data offset */
- swheader =
- ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
- (((pad +
- SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
-
- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
-
-#ifdef BCMDBG
- tx_packets[pkt->priority]++;
- if (BRCMF_BYTES_ON() &&
- (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
- (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
- printk(KERN_DEBUG "Tx Frame:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
- } else if (BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "TxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, min_t(u16, len, 16));
- }
-#endif
-
- /* Raise len to next SDIO block to eliminate tail command */
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- u16 pad = bus->blocksize - (len % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize))
- len += pad;
- } else if (len % BRCMF_SDALIGN) {
- len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
- }
-
- /* Some controllers have trouble with odd bytes -- round to even */
- if (forcealign && (len & (ALIGNMENT - 1))) {
- len = roundup(len, ALIGNMENT);
- }
-
- do {
- ret = brcmf_sdbrcm_send_buf(bus, brcmf_sdcard_cur_sbwad(card),
- SDIO_FUNC_2, F2SYNC, frame, len, pkt, NULL, NULL);
- bus->f2txdata++;
-
- if (ret < 0) {
- /* On failure, abort the command
- and terminate the frame */
- BRCMF_INFO(("%s: sdio error %d, abort command and "
- "terminate frame.\n", __func__, ret));
- bus->tx_sderrs++;
-
- brcmf_sdcard_abort(card, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
- NULL);
- bus->f1regdata++;
-
- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
-
- }
- if (ret == 0)
- bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
-
- } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
-
-done:
- /* restore pkt buffer pointer before calling tx complete routine */
- skb_pull(pkt, SDPCM_HDRLEN + pad);
- brcmf_sdbrcm_sdunlock(bus);
- brcmf_txcomplete(bus->drvr, pkt, ret != 0);
- brcmf_sdbrcm_sdlock(bus);
-
- if (free_pkt)
- brcmu_pkt_buf_free_skb(pkt);
-
- return ret;
-}
-
-int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
-{
- int ret = -EBADE;
- uint datalen, prec;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- datalen = pkt->len;
-
-#ifdef SDTEST
- /* Push the test header if doing loopback */
- if (bus->ext_loop) {
- u8 *data;
- skb_push(pkt, SDPCM_TEST_HDRLEN);
- data = pkt->data;
- *data++ = SDPCM_TEST_ECHOREQ;
- *data++ = (u8) bus->loopid++;
- *data++ = (datalen >> 0);
- *data++ = (datalen >> 8);
- datalen += SDPCM_TEST_HDRLEN;
- }
-#endif /* SDTEST */
-
- /* Add space for the header */
- skb_push(pkt, SDPCM_HDRLEN);
- /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
-
- prec = PRIO2PREC((pkt->priority & PRIOMASK));
-
- /* Check for existing queue, current flow-control,
- pending event, or pending clock */
- if (brcmf_deferred_tx || bus->fcstate || pktq_len(&bus->txq)
- || bus->dpc_sched || (!DATAOK(bus))
- || (bus->flowcontrol & NBITVAL(prec))
- || (bus->clkstate != CLK_AVAIL)) {
- BRCMF_TRACE(("%s: deferring pktq len %d\n", __func__,
- pktq_len(&bus->txq)));
- bus->fcqueued++;
-
- /* Priority based enq */
- spin_lock_bh(&bus->txqlock);
- if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) {
- skb_pull(pkt, SDPCM_HDRLEN);
- brcmf_txcomplete(bus->drvr, pkt, false);
- brcmu_pkt_buf_free_skb(pkt);
- BRCMF_ERROR(("%s: out of bus->txq !!!\n", __func__));
- ret = -ENOSR;
- } else {
- ret = 0;
- }
- spin_unlock_bh(&bus->txqlock);
-
- if (pktq_len(&bus->txq) >= TXHI)
- brcmf_txflowcontrol(bus->drvr, 0, ON);
-
-#ifdef BCMDBG
- if (pktq_plen(&bus->txq, prec) > qcount[prec])
- qcount[prec] = pktq_plen(&bus->txq, prec);
-#endif
- /* Schedule DPC if needed to send queued packet(s) */
- if (brcmf_deferred_tx && !bus->dpc_sched) {
- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
- }
- } else {
- /* Lock: we're about to use shared data/code (and SDIO) */
- brcmf_sdbrcm_sdlock(bus);
-
- /* Otherwise, send it now */
- BUS_WAKE(bus);
- /* Make sure back plane ht clk is on, no pending allowed */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
-
-#ifndef SDTEST
- BRCMF_TRACE(("%s: calling txpkt\n", __func__));
- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
-#else
- ret = brcmf_sdbrcm_txpkt(bus, pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL :
- SDPCM_DATA_CHANNEL), true);
-#endif
- if (ret)
- bus->drvr->tx_errors++;
- else
- bus->drvr->dstats.tx_bytes += datalen;
-
- if (bus->idletime == BRCMF_IDLE_IMMEDIATE &&
- !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
- }
-
- brcmf_sdbrcm_sdunlock(bus);
- }
-
- return ret;
+ if (bus->sleeping)
+ brcmf_sdbrcm_bussleep(bus, false);
}
-static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
+static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
{
- struct sk_buff *pkt;
u32 intstatus = 0;
+ u32 hmb_data;
+ u8 fcbits;
uint retries = 0;
- int ret = 0, prec_out;
- uint cnt = 0;
- uint datalen;
- u8 tx_prec_map;
-
- struct brcmf_pub *drvr = bus->drvr;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- tx_prec_map = ~bus->flowcontrol;
-
- /* Send frames until the limit or some other event */
- for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
- spin_lock_bh(&bus->txqlock);
- pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
- if (pkt == NULL) {
- spin_unlock_bh(&bus->txqlock);
- break;
- }
- spin_unlock_bh(&bus->txqlock);
- datalen = pkt->len - SDPCM_HDRLEN;
-
-#ifndef SDTEST
- ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
-#else
- ret = brcmf_sdbrcm_txpkt(bus, pkt,
- (bus->ext_loop ? SDPCM_TEST_CHANNEL :
- SDPCM_DATA_CHANNEL), true);
-#endif
- if (ret)
- bus->drvr->tx_errors++;
- else
- bus->drvr->dstats.tx_bytes += datalen;
-
- /* In poll mode, need to check for other events */
- if (!bus->intr && cnt) {
- /* Check device status, signal pending interrupt */
- r_sdreg32(bus, &intstatus,
- offsetof(struct sdpcmd_regs, intstatus),
- &retries);
- bus->f2txdata++;
- if (brcmf_sdcard_regfail(bus->card))
- break;
- if (intstatus & bus->hostintmask)
- bus->ipend = true;
- }
- }
-
- /* Deflow-control stack if needed */
- if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
- drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
- brcmf_txflowcontrol(drvr, 0, OFF);
-
- return cnt;
-}
-
-int
-brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
-{
- u8 *frame;
- u16 len;
- u32 swheader;
- uint retries = 0;
- struct brcmf_sdio_card *card = bus->card;
- u8 doff = 0;
- int ret = -1;
- int i;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (bus->drvr->dongle_reset)
- return -EIO;
-
- /* Back the pointer to make a room for bus header */
- frame = msg - SDPCM_HDRLEN;
- len = (msglen += SDPCM_HDRLEN);
-
- /* Add alignment padding (optional for ctl frames) */
- if (brcmf_alignctl) {
- doff = ((unsigned long)frame % BRCMF_SDALIGN);
- if (doff) {
- frame -= doff;
- len += doff;
- msglen += doff;
- memset(frame, 0, doff + SDPCM_HDRLEN);
- }
- /* precondition: doff < BRCMF_SDALIGN */
- }
- doff += SDPCM_HDRLEN;
-
- /* Round send length to next SDIO block */
- if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
- u16 pad = bus->blocksize - (len % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize))
- len += pad;
- } else if (len % BRCMF_SDALIGN) {
- len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
- }
-
- /* Satisfy length-alignment requirements */
- if (forcealign && (len & (ALIGNMENT - 1)))
- len = roundup(len, ALIGNMENT);
-
- /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
-
- /* Need to lock here to protect txseq and SDIO tx calls */
- brcmf_sdbrcm_sdlock(bus);
-
- BUS_WAKE(bus);
-
- /* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
-
- /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
- *(u16 *) frame = cpu_to_le16((u16) msglen);
- *(((u16 *) frame) + 1) = cpu_to_le16(~msglen);
-
- /* Software tag: channel, sequence number, data offset */
- swheader =
- ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
- SDPCM_CHANNEL_MASK)
- | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
- SDPCM_DOFFSET_MASK);
- put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
- put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
-
- if (!DATAOK(bus)) {
- BRCMF_INFO(("%s: No bus credit bus->tx_max %d,"
- " bus->tx_seq %d\n", __func__,
- bus->tx_max, bus->tx_seq));
- bus->ctrl_frame_stat = true;
- /* Send from dpc */
- bus->ctrl_frame_buf = frame;
- bus->ctrl_frame_len = len;
-
- brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
-
- if (bus->ctrl_frame_stat == false) {
- BRCMF_INFO(("%s: ctrl_frame_stat == false\n",
- __func__));
- ret = 0;
- } else {
- BRCMF_INFO(("%s: ctrl_frame_stat == true\n", __func__));
- ret = -1;
- }
- }
-
- if (ret == -1) {
-#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
- printk(KERN_DEBUG "Tx Frame:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, len);
- } else if (BRCMF_HDRS_ON()) {
- printk(KERN_DEBUG "TxHdr:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
- frame, min_t(u16, len, 16));
- }
-#endif
-
- do {
- bus->ctrl_frame_stat = false;
- ret = brcmf_sdbrcm_send_buf(bus,
- brcmf_sdcard_cur_sbwad(card), SDIO_FUNC_2,
- F2SYNC, frame, len, NULL, NULL, NULL);
-
- if (ret < 0) {
- /* On failure, abort the command and
- terminate the frame */
- BRCMF_INFO(("%s: sdio error %d, abort command "
- "and terminate frame.\n",
- __func__, ret));
- bus->tx_sderrs++;
-
- brcmf_sdcard_abort(card, SDIO_FUNC_2);
-
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
- bus->f1regdata++;
-
- for (i = 0; i < 3; i++) {
- u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(card,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(card,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
- bus->f1regdata += 2;
- if ((hi == 0) && (lo == 0))
- break;
- }
-
- }
- if (ret == 0) {
- bus->tx_seq =
- (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- }
- } while ((ret < 0) && retries++ < TXRETRIES);
- }
-
- if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
- }
-
- brcmf_sdbrcm_sdunlock(bus);
-
- if (ret)
- bus->drvr->tx_ctlerrs++;
- else
- bus->drvr->tx_ctlpkts++;
-
- return ret ? -EIO : 0;
-}
-
-int brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
-{
- int timeleft;
- uint rxlen = 0;
- bool pending;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (bus->drvr->dongle_reset)
- return -EIO;
-
- /* Wait until control frame is available */
- timeleft = brcmf_os_ioctl_resp_wait(bus->drvr, &bus->rxlen, &pending);
-
- brcmf_sdbrcm_sdlock(bus);
- rxlen = bus->rxlen;
- memcpy(msg, bus->rxctl, min(msglen, rxlen));
- bus->rxlen = 0;
- brcmf_sdbrcm_sdunlock(bus);
-
- if (rxlen) {
- BRCMF_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
- __func__, rxlen, msglen));
- } else if (timeleft == 0) {
- BRCMF_ERROR(("%s: resumed on timeout\n", __func__));
-#ifdef BCMDBG
- brcmf_sdbrcm_sdlock(bus);
- brcmf_sdbrcm_checkdied(bus, NULL, 0);
- brcmf_sdbrcm_sdunlock(bus);
-#endif /* BCMDBG */
- } else if (pending == true) {
- BRCMF_CTL(("%s: cancelled\n", __func__));
- return -ERESTARTSYS;
- } else {
- BRCMF_CTL(("%s: resumed for unknown reason?\n", __func__));
-#ifdef BCMDBG
- brcmf_sdbrcm_sdlock(bus);
- brcmf_sdbrcm_checkdied(bus, NULL, 0);
- brcmf_sdbrcm_sdunlock(bus);
-#endif /* BCMDBG */
- }
-
- if (rxlen)
- bus->drvr->rx_ctlpkts++;
- else
- bus->drvr->rx_ctlerrs++;
-
- return rxlen ? (int)rxlen : -ETIMEDOUT;
-}
-
-/* IOVar table */
-enum {
- IOV_INTR = 1,
- IOV_POLLRATE,
- IOV_SDREG,
- IOV_SBREG,
- IOV_SDCIS,
- IOV_MEMBYTES,
- IOV_MEMSIZE,
-#ifdef BCMDBG
- IOV_CHECKDIED,
- IOV_CONS,
- IOV_DCONSOLE_POLL,
-#endif
- IOV_DOWNLOAD,
- IOV_FORCEEVEN,
- IOV_SDIOD_DRIVE,
- IOV_READAHEAD,
- IOV_SDRXCHAIN,
- IOV_ALIGNCTL,
- IOV_SDALIGN,
- IOV_DEVRESET,
- IOV_CPU,
-#ifdef SDTEST
- IOV_PKTGEN,
- IOV_EXTLOOP,
-#endif /* SDTEST */
- IOV_SPROM,
- IOV_TXBOUND,
- IOV_RXBOUND,
- IOV_TXMINMAX,
- IOV_IDLETIME,
- IOV_IDLECLOCK,
- IOV_SD1IDLE,
- IOV_SLEEP,
- IOV_WDTICK,
- IOV_VARS
-};
-
-const struct brcmu_iovar brcmf_sdio_iovars[] = {
- {"intr", IOV_INTR, 0, IOVT_BOOL, 0},
- {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0},
- {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0},
- {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0},
- {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0},
- {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0},
- {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int)},
- {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0},
- {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0},
- {"vars", IOV_VARS, 0, IOVT_BUFFER, 0},
- {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0},
- {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0},
- {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0},
- {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0},
- {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0},
- {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0},
- {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0},
-#ifdef BCMDBG
- {"cons", IOV_CONS, 0, IOVT_BUFFER, 0}
- ,
- {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0}
- ,
- {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)}
- ,
- {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(struct brcmf_sdreg)}
- ,
- {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, BRCMF_IOCTL_MAXLEN}
- ,
- {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0}
- ,
- {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0}
- ,
- {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0}
- ,
- {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0}
- ,
- {"cpu", IOV_CPU, 0, IOVT_BOOL, 0}
- ,
- {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0}
- ,
-#endif /* BCMDBG */
-#ifdef SDTEST
- {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0}
- ,
- {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(struct brcmf_pktgen)}
- ,
-#endif /* SDTEST */
-
- {NULL, 0, 0, 0, 0}
-};
-
-static void
-brcmf_dump_pct(struct brcmu_strbuf *strbuf, char *desc, uint num, uint div)
-{
- uint q1, q2;
-
- if (!div) {
- brcmu_bprintf(strbuf, "%s N/A", desc);
- } else {
- q1 = num / div;
- q2 = (100 * (num - (q1 * div))) / div;
- brcmu_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
- }
-}
-void brcmf_sdbrcm_bus_dump(struct brcmf_pub *drvr, struct brcmu_strbuf *strbuf)
-{
- struct brcmf_bus *bus = drvr->bus;
-
- brcmu_bprintf(strbuf, "Bus SDIO structure:\n");
- brcmu_bprintf(strbuf,
- "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
- bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
- brcmu_bprintf(strbuf,
- "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
- bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max,
- bus->rxskip, bus->rxlen, bus->rx_seq);
- brcmu_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
- bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
- brcmu_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
- bus->pollrate, bus->pollcnt, bus->regfails);
-
- brcmu_bprintf(strbuf, "\nAdditional counters:\n");
- brcmu_bprintf(strbuf,
- "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
- bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
- bus->rxc_errors);
- brcmu_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
- bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
- brcmu_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
- bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
- brcmu_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
- bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
- brcmu_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs"
- " %d\n",
- (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs,
- bus->f2rxdata, bus->f2txdata, bus->f1regdata);
- {
- brcmf_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->drvr->rx_packets,
- (bus->f2rxhdrs + bus->f2rxdata));
- brcmf_dump_pct(strbuf, ", pkts/f1sd", bus->drvr->rx_packets,
- bus->f1regdata);
- brcmf_dump_pct(strbuf, ", pkts/sd", bus->drvr->rx_packets,
- (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
- brcmf_dump_pct(strbuf, ", pkts/int", bus->drvr->rx_packets,
- bus->intrcount);
- brcmu_bprintf(strbuf, "\n");
-
- brcmf_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
- bus->drvr->rx_packets);
- brcmf_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts,
- bus->rxglomframes);
- brcmu_bprintf(strbuf, "\n");
-
- brcmf_dump_pct(strbuf, "Tx: pkts/f2wr", bus->drvr->tx_packets,
- bus->f2txdata);
- brcmf_dump_pct(strbuf, ", pkts/f1sd", bus->drvr->tx_packets,
- bus->f1regdata);
- brcmf_dump_pct(strbuf, ", pkts/sd", bus->drvr->tx_packets,
- (bus->f2txdata + bus->f1regdata));
- brcmf_dump_pct(strbuf, ", pkts/int", bus->drvr->tx_packets,
- bus->intrcount);
- brcmu_bprintf(strbuf, "\n");
-
- brcmf_dump_pct(strbuf, "Total: pkts/f2rw",
- (bus->drvr->tx_packets + bus->drvr->rx_packets),
- (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
- brcmf_dump_pct(strbuf, ", pkts/f1sd",
- (bus->drvr->tx_packets + bus->drvr->rx_packets),
- bus->f1regdata);
- brcmf_dump_pct(strbuf, ", pkts/sd",
- (bus->drvr->tx_packets + bus->drvr->rx_packets),
- (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata +
- bus->f1regdata));
- brcmf_dump_pct(strbuf, ", pkts/int",
- (bus->drvr->tx_packets + bus->drvr->rx_packets),
- bus->intrcount);
- brcmu_bprintf(strbuf, "\n\n");
- }
-
-#ifdef SDTEST
- if (bus->pktgen_count) {
- brcmu_bprintf(strbuf, "pktgen config and count:\n");
- brcmu_bprintf(strbuf,
- "freq %d count %d print %d total %d min %d len %d\n",
- bus->pktgen_freq, bus->pktgen_count,
- bus->pktgen_print, bus->pktgen_total,
- bus->pktgen_minlen, bus->pktgen_maxlen);
- brcmu_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
- bus->pktgen_sent, bus->pktgen_rcvd,
- bus->pktgen_fail);
- }
-#endif /* SDTEST */
-#ifdef BCMDBG
- brcmu_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
- bus->dpc_sched, " not ");
- brcmu_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize,
- bus->roundup);
-#endif /* BCMDBG */
- brcmu_bprintf(strbuf,
- "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
- bus->clkstate, bus->activity, bus->idletime, bus->idlecount,
- bus->sleeping);
-}
-
-void brcmf_bus_clearcounts(struct brcmf_pub *drvr)
-{
- struct brcmf_bus *bus = (struct brcmf_bus *) drvr->bus;
-
- bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
- bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
- bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
- bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
- bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
- bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
-}
+ brcmf_dbg(TRACE, "Enter\n");
-#ifdef SDTEST
-static int brcmf_sdbrcm_pktgen_get(struct brcmf_bus *bus, u8 *arg)
-{
- struct brcmf_pktgen pktgen;
-
- pktgen.version = BRCMF_PKTGEN_VERSION;
- pktgen.freq = bus->pktgen_freq;
- pktgen.count = bus->pktgen_count;
- pktgen.print = bus->pktgen_print;
- pktgen.total = bus->pktgen_total;
- pktgen.minlen = bus->pktgen_minlen;
- pktgen.maxlen = bus->pktgen_maxlen;
- pktgen.numsent = bus->pktgen_sent;
- pktgen.numrcvd = bus->pktgen_rcvd;
- pktgen.numfail = bus->pktgen_fail;
- pktgen.mode = bus->pktgen_mode;
- pktgen.stop = bus->pktgen_stop;
-
- memcpy(arg, &pktgen, sizeof(pktgen));
-
- return 0;
-}
-
-static int brcmf_sdbrcm_pktgen_set(struct brcmf_bus *bus, u8 *arg)
-{
- struct brcmf_pktgen pktgen;
- uint oldcnt, oldmode;
-
- memcpy(&pktgen, arg, sizeof(pktgen));
- if (pktgen.version != BRCMF_PKTGEN_VERSION)
- return -EINVAL;
-
- oldcnt = bus->pktgen_count;
- oldmode = bus->pktgen_mode;
-
- bus->pktgen_freq = pktgen.freq;
- bus->pktgen_count = pktgen.count;
- bus->pktgen_print = pktgen.print;
- bus->pktgen_total = pktgen.total;
- bus->pktgen_minlen = pktgen.minlen;
- bus->pktgen_maxlen = pktgen.maxlen;
- bus->pktgen_mode = pktgen.mode;
- bus->pktgen_stop = pktgen.stop;
-
- bus->pktgen_tick = bus->pktgen_ptick = 0;
- bus->pktgen_len = max(bus->pktgen_len, bus->pktgen_minlen);
- bus->pktgen_len = min(bus->pktgen_len, bus->pktgen_maxlen);
-
- /* Clear counts for a new pktgen (mode change, or was stopped) */
- if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
- bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
-
- return 0;
-}
-#endif /* SDTEST */
-
-static int
-brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
- uint size)
-{
- int bcmerror = 0;
- u32 sdaddr;
- uint dsize;
-
- /* Determine initial transfer parameters */
- sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
- if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
- dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
- else
- dsize = size;
-
- /* Set the backplane window to include the start address */
- bcmerror = brcmf_sdbrcm_set_siaddr_window(bus, address);
- if (bcmerror) {
- BRCMF_ERROR(("%s: window change failed\n", __func__));
- goto xfer_done;
- }
+ /* Read mailbox data and ack that we did so */
+ r_sdreg32(bus, &hmb_data,
+ offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
- /* Do the transfer(s) */
- while (size) {
- BRCMF_INFO(("%s: %s %d bytes at offset 0x%08x in window"
- " 0x%08x\n", __func__, (write ? "write" : "read"),
- dsize, sdaddr, (address & SBSDIO_SBWINDOW_MASK)));
- bcmerror =
- brcmf_sdcard_rwdata(bus->card, write, sdaddr, data, dsize);
- if (bcmerror) {
- BRCMF_ERROR(("%s: membytes transfer failed\n",
- __func__));
- break;
- }
+ if (retries <= retry_limit)
+ w_sdreg32(bus, SMB_INT_ACK,
+ offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ bus->f1regdata += 2;
- /* Adjust for next transfer (if any) */
- size -= dsize;
- if (size) {
- data += dsize;
- address += dsize;
- bcmerror = brcmf_sdbrcm_set_siaddr_window(bus, address);
- if (bcmerror) {
- BRCMF_ERROR(("%s: window change failed\n",
- __func__));
- break;
- }
- sdaddr = 0;
- dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
- }
- }
+ /* Dongle recomposed rx frames, accept them again */
+ if (hmb_data & HMB_DATA_NAKHANDLED) {
+ brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n",
+ bus->rx_seq);
+ if (!bus->rxskip)
+ brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n");
-xfer_done:
- /* Return the window to backplane enumeration space for core access */
- if (brcmf_sdbrcm_set_siaddr_window(bus,
- brcmf_sdcard_cur_sbwad(bus->card))) {
- BRCMF_ERROR(("%s: FAILED to set window back to 0x%x\n",
- __func__, brcmf_sdcard_cur_sbwad(bus->card)));
+ bus->rxskip = false;
+ intstatus |= I_HMB_FRAME_IND;
}
- return bcmerror;
-}
-
-#ifdef BCMDBG
-static int brcmf_sdbrcm_readshared(struct brcmf_bus *bus, struct sdpcm_shared *sh)
-{
- u32 addr;
- int rv;
-
- /* Read last word in memory to determine address of
- sdpcm_shared structure */
- rv = brcmf_sdbrcm_membytes(bus, false, bus->ramsize - 4, (u8 *)&addr,
- 4);
- if (rv < 0)
- return rv;
-
- addr = le32_to_cpu(addr);
-
- BRCMF_INFO(("sdpcm_shared address 0x%08X\n", addr));
-
/*
- * Check if addr is valid.
- * NVRAM length at the end of memory should have been overwritten.
+ * DEVREADY does not occur with gSPI.
*/
- if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
- BRCMF_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n",
- __func__, addr));
- return -EBADE;
- }
-
- /* Read rte_shared structure */
- rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *) sh,
- sizeof(struct sdpcm_shared));
- if (rv < 0)
- return rv;
-
- /* Endianness */
- sh->flags = le32_to_cpu(sh->flags);
- sh->trap_addr = le32_to_cpu(sh->trap_addr);
- sh->assert_exp_addr = le32_to_cpu(sh->assert_exp_addr);
- sh->assert_file_addr = le32_to_cpu(sh->assert_file_addr);
- sh->assert_line = le32_to_cpu(sh->assert_line);
- sh->console_addr = le32_to_cpu(sh->console_addr);
- sh->msgtrace_addr = le32_to_cpu(sh->msgtrace_addr);
-
- if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
- BRCMF_ERROR(("%s: sdpcm_shared version %d in brcmf "
- "is different than sdpcm_shared version %d in dongle\n",
- __func__, SDPCM_SHARED_VERSION,
- sh->flags & SDPCM_SHARED_VERSION_MASK));
- return -EBADE;
- }
-
- return 0;
-}
-
-static int brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, u8 *data, uint size)
-{
- int bcmerror = 0;
- uint msize = 512;
- char *mbuffer = NULL;
- uint maxstrlen = 256;
- char *str = NULL;
- struct brcmf_trap tr;
- struct sdpcm_shared sdpcm_shared;
- struct brcmu_strbuf strbuf;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (data == NULL) {
- /*
- * Called after a rx ctrl timeout. "data" is NULL.
- * allocate memory to trace the trap or assert.
- */
- size = msize;
- mbuffer = data = kmalloc(msize, GFP_ATOMIC);
- if (mbuffer == NULL) {
- BRCMF_ERROR(("%s: kmalloc(%d) failed\n", __func__,
- msize));
- bcmerror = -ENOMEM;
- goto done;
- }
- }
-
- str = kmalloc(maxstrlen, GFP_ATOMIC);
- if (str == NULL) {
- BRCMF_ERROR(("%s: kmalloc(%d) failed\n", __func__, maxstrlen));
- bcmerror = -ENOMEM;
- goto done;
- }
-
- bcmerror = brcmf_sdbrcm_readshared(bus, &sdpcm_shared);
- if (bcmerror < 0)
- goto done;
-
- brcmu_binit(&strbuf, data, size);
-
- brcmu_bprintf(&strbuf,
- "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
- sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
-
- if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
- /* NOTE: Misspelled assert is intentional - DO NOT FIX.
- * (Avoids conflict with real asserts for programmatic
- * parsing of output.)
- */
- brcmu_bprintf(&strbuf, "Assrt not built in dongle\n");
- }
-
- if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) ==
- 0) {
- /* NOTE: Misspelled assert is intentional - DO NOT FIX.
- * (Avoids conflict with real asserts for programmatic
- * parsing of output.)
- */
- brcmu_bprintf(&strbuf, "No trap%s in dongle",
- (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
- ? "/assrt" : "");
- } else {
- if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
- /* Download assert */
- brcmu_bprintf(&strbuf, "Dongle assert");
- if (sdpcm_shared.assert_exp_addr != 0) {
- str[0] = '\0';
- bcmerror = brcmf_sdbrcm_membytes(bus, false,
- sdpcm_shared.assert_exp_addr,
- (u8 *) str, maxstrlen);
- if (bcmerror < 0)
- goto done;
-
- str[maxstrlen - 1] = '\0';
- brcmu_bprintf(&strbuf, " expr \"%s\"", str);
- }
-
- if (sdpcm_shared.assert_file_addr != 0) {
- str[0] = '\0';
- bcmerror = brcmf_sdbrcm_membytes(bus, false,
- sdpcm_shared.assert_file_addr,
- (u8 *) str, maxstrlen);
- if (bcmerror < 0)
- goto done;
-
- str[maxstrlen - 1] = '\0';
- brcmu_bprintf(&strbuf, " file \"%s\"", str);
- }
-
- brcmu_bprintf(&strbuf, " line %d ",
- sdpcm_shared.assert_line);
- }
-
- if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
- bcmerror = brcmf_sdbrcm_membytes(bus, false,
- sdpcm_shared.trap_addr, (u8 *)&tr,
- sizeof(struct brcmf_trap));
- if (bcmerror < 0)
- goto done;
-
- brcmu_bprintf(&strbuf,
- "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
- "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
- "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
- tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13,
- tr.r14, tr.pc, sdpcm_shared.trap_addr,
- tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5,
- tr.r6, tr.r7);
- }
- }
-
- if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP))
- BRCMF_ERROR(("%s: %s\n", __func__, strbuf.origbuf));
-
-#ifdef BCMDBG
- if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
- /* Mem dump to a file on device */
- brcmf_sdbrcm_mem_dump(bus);
- }
-#endif /* BCMDBG */
-
-done:
- kfree(mbuffer);
- kfree(str);
-
- return bcmerror;
-}
-
-static int brcmf_sdbrcm_mem_dump(struct brcmf_bus *bus)
-{
- int ret = 0;
- int size; /* Full mem size */
- int start = 0; /* Start address */
- int read_size = 0; /* Read size of each iteration */
- u8 *buf = NULL, *databuf = NULL;
-
- /* Get full mem size */
- size = bus->ramsize;
- buf = kmalloc(size, GFP_ATOMIC);
- if (!buf) {
- BRCMF_ERROR(("%s: Out of memory (%d bytes)\n", __func__, size));
- return -1;
- }
-
- /* Read mem content */
- printk(KERN_DEBUG "Dump dongle memory");
- databuf = buf;
- while (size) {
- read_size = min(MEMBLOCK, size);
- ret = brcmf_sdbrcm_membytes(bus, false, start, databuf,
- read_size);
- if (ret) {
- BRCMF_ERROR(("%s: Error membytes %d\n", __func__, ret));
- kfree(buf);
- return -1;
- }
- printk(".");
-
- /* Decrement size and increment start address */
- size -= read_size;
- start += read_size;
- databuf += read_size;
- }
- printk(KERN_DEBUG "Done\n");
-
- /* free buf before return !!! */
- if (brcmf_write_to_file(bus->drvr, buf, bus->ramsize)) {
- BRCMF_ERROR(("%s: Error writing to files\n", __func__));
- return -1;
- }
-
- /* buf free handled in brcmf_write_to_file, not here */
- return 0;
-}
-
-#define CONSOLE_LINE_MAX 192
-
-static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
-{
- struct brcmf_console *c = &bus->console;
- u8 line[CONSOLE_LINE_MAX], ch;
- u32 n, idx, addr;
- int rv;
-
- /* Don't do anything until FWREADY updates console address */
- if (bus->console_addr == 0)
- return 0;
-
- /* Read console log struct */
- addr = bus->console_addr + offsetof(struct rte_console, log);
- rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log,
- sizeof(c->log));
- if (rv < 0)
- return rv;
-
- /* Allocate console buffer (one time only) */
- if (c->buf == NULL) {
- c->bufsize = le32_to_cpu(c->log.buf_size);
- c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
- if (c->buf == NULL)
- return -ENOMEM;
- }
-
- idx = le32_to_cpu(c->log.idx);
-
- /* Protect against corrupt value */
- if (idx > c->bufsize)
- return -EBADE;
-
- /* Skip reading the console buffer if the index pointer
- has not moved */
- if (idx == c->last)
- return 0;
-
- /* Read the console buffer */
- addr = le32_to_cpu(c->log.buf);
- rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
- if (rv < 0)
- return rv;
-
- while (c->last != idx) {
- for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
- if (c->last == idx) {
- /* This would output a partial line.
- * Instead, back up
- * the buffer pointer and output this
- * line next time around.
- */
- if (c->last >= n)
- c->last -= n;
- else
- c->last = c->bufsize - n;
- goto break2;
- }
- ch = c->buf[c->last];
- c->last = (c->last + 1) % c->bufsize;
- if (ch == '\n')
- break;
- line[n] = ch;
- }
-
- if (n > 0) {
- if (line[n - 1] == '\r')
- n--;
- line[n] = 0;
- printk(KERN_DEBUG "CONSOLE: %s\n", line);
- }
- }
-break2:
-
- return 0;
-}
-#endif /* BCMDBG */
-
-int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
-{
- int bcmerror = 0;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- /* Basic sanity checks */
- if (bus->drvr->up) {
- bcmerror = -EISCONN;
- goto err;
- }
- if (!len) {
- bcmerror = -EOVERFLOW;
- goto err;
- }
-
- /* Free the old ones and replace with passed variables */
- kfree(bus->vars);
-
- bus->vars = kmalloc(len, GFP_ATOMIC);
- bus->varsz = bus->vars ? len : 0;
- if (bus->vars == NULL) {
- bcmerror = -ENOMEM;
- goto err;
- }
-
- /* Copy the passed variables, which should include the
- terminating double-null */
- memcpy(bus->vars, arg, bus->varsz);
-err:
- return bcmerror;
-}
-
-static int
-brcmf_sdbrcm_doiovar(struct brcmf_bus *bus, const struct brcmu_iovar *vi, u32 actionid,
- const char *name, void *params, int plen, void *arg, int len,
- int val_size)
-{
- int bcmerror = 0;
- s32 int_val = 0;
- bool bool_val = 0;
-
- BRCMF_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p "
- "len %d val_size %d\n", __func__, actionid, name, params,
- plen, arg, len, val_size));
-
- bcmerror = brcmu_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid));
- if (bcmerror != 0)
- goto exit;
-
- if (plen >= (int)sizeof(int_val))
- memcpy(&int_val, params, sizeof(int_val));
-
- bool_val = (int_val != 0) ? true : false;
-
- /* Some ioctls use the bus */
- brcmf_sdbrcm_sdlock(bus);
-
- /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
- if (bus->drvr->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
- actionid == IOV_GVAL(IOV_DEVRESET))) {
- bcmerror = -EPERM;
- goto exit;
- }
-
- /* Handle sleep stuff before any clock mucking */
- if (vi->varid == IOV_SLEEP) {
- if (IOV_ISSET(actionid)) {
- bcmerror = brcmf_sdbrcm_bussleep(bus, bool_val);
- } else {
- int_val = (s32) bus->sleeping;
- memcpy(arg, &int_val, val_size);
- }
- goto exit;
- }
-
- /* Request clock to allow SDIO accesses */
- if (!bus->drvr->dongle_reset) {
- BUS_WAKE(bus);
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- }
-
- switch (actionid) {
- case IOV_GVAL(IOV_INTR):
- int_val = (s32) bus->intr;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_INTR):
- bus->intr = bool_val;
- bus->intdis = false;
- if (bus->drvr->up) {
- BRCMF_INTR(("%s: %s SDIO interrupts\n", __func__,
- bus->intr ? "enable" : "disable"));
- if (bus->intr) {
- brcmf_sdcard_intr_enable(bus->card);
- } else {
- brcmf_sdcard_intr_disable(bus->card);
- }
- }
- break;
-
- case IOV_GVAL(IOV_POLLRATE):
- int_val = (s32) bus->pollrate;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_POLLRATE):
- bus->pollrate = (uint) int_val;
- bus->poll = (bus->pollrate != 0);
- break;
-
- case IOV_GVAL(IOV_IDLETIME):
- int_val = bus->idletime;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_IDLETIME):
- if ((int_val < 0) && (int_val != BRCMF_IDLE_IMMEDIATE))
- bcmerror = -EINVAL;
- else
- bus->idletime = int_val;
- break;
-
- case IOV_GVAL(IOV_IDLECLOCK):
- int_val = (s32) bus->idleclock;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_IDLECLOCK):
- bus->idleclock = int_val;
- break;
-
- case IOV_GVAL(IOV_SD1IDLE):
- int_val = (s32) sd1idle;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_SD1IDLE):
- sd1idle = bool_val;
- break;
-
- case IOV_SVAL(IOV_MEMBYTES):
- case IOV_GVAL(IOV_MEMBYTES):
- {
- u32 address;
- uint size, dsize;
- u8 *data;
-
- bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
-
- address = (u32) int_val;
- memcpy(&int_val, (char *)params + sizeof(int_val),
- sizeof(int_val));
- size = (uint) int_val;
-
- /* Do some validation */
- dsize = set ? plen - (2 * sizeof(int)) : len;
- if (dsize < size) {
- BRCMF_ERROR(("%s: error on %s membytes, addr "
- "0x%08x size %d dsize %d\n",
- __func__, (set ? "set" : "get"),
- address, size, dsize));
- bcmerror = -EINVAL;
- break;
- }
-
- BRCMF_INFO(("%s: Request to %s %d bytes at address "
- "0x%08x\n", __func__,
- (set ? "write" : "read"), size, address));
-
- /* If we know about SOCRAM, check for a fit */
- if ((bus->orig_ramsize) &&
- ((address > bus->orig_ramsize)
- || (address + size > bus->orig_ramsize))) {
- BRCMF_ERROR(("%s: ramsize 0x%08x doesn't have"
- " %d bytes at 0x%08x\n", __func__,
- bus->orig_ramsize, size, address));
- bcmerror = -EINVAL;
- break;
- }
-
- /* Generate the actual data pointer */
- data =
- set ? (u8 *) params +
- 2 * sizeof(int) : (u8 *) arg;
-
- /* Call to do the transfer */
- bcmerror = brcmf_sdbrcm_membytes(bus, set, address,
- data, size);
-
- break;
- }
-
- case IOV_GVAL(IOV_MEMSIZE):
- int_val = (s32) bus->ramsize;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_GVAL(IOV_SDIOD_DRIVE):
- int_val = (s32) brcmf_sdiod_drive_strength;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_SDIOD_DRIVE):
- brcmf_sdiod_drive_strength = int_val;
- brcmf_sdbrcm_sdiod_drive_strength_init(bus,
- brcmf_sdiod_drive_strength);
- break;
-
- case IOV_SVAL(IOV_DOWNLOAD):
- bcmerror = brcmf_sdbrcm_download_state(bus, bool_val);
- break;
-
- case IOV_SVAL(IOV_VARS):
- bcmerror = brcmf_sdbrcm_downloadvars(bus, arg, len);
- break;
-
- case IOV_GVAL(IOV_READAHEAD):
- int_val = (s32) brcmf_readahead;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_READAHEAD):
- if (bool_val && !brcmf_readahead)
- bus->nextlen = 0;
- brcmf_readahead = bool_val;
- break;
-
- case IOV_GVAL(IOV_SDRXCHAIN):
- int_val = (s32) bus->use_rxchain;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_SDRXCHAIN):
- if (bool_val && !bus->sd_rxchain)
- bcmerror = -ENOTSUPP;
- else
- bus->use_rxchain = bool_val;
- break;
- case IOV_GVAL(IOV_ALIGNCTL):
- int_val = (s32) brcmf_alignctl;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_ALIGNCTL):
- brcmf_alignctl = bool_val;
- break;
-
- case IOV_GVAL(IOV_SDALIGN):
- int_val = BRCMF_SDALIGN;
- memcpy(arg, &int_val, val_size);
- break;
-
-#ifdef BCMDBG
- case IOV_GVAL(IOV_VARS):
- if (bus->varsz < (uint) len)
- memcpy(arg, bus->vars, bus->varsz);
+ if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
+ bus->sdpcm_ver =
+ (hmb_data & HMB_DATA_VERSION_MASK) >>
+ HMB_DATA_VERSION_SHIFT;
+ if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
+ brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, "
+ "expecting %d\n",
+ bus->sdpcm_ver, SDPCM_PROT_VERSION);
else
- bcmerror = -EOVERFLOW;
- break;
-#endif /* BCMDBG */
-
-#ifdef BCMDBG
- case IOV_GVAL(IOV_DCONSOLE_POLL):
- int_val = (s32) brcmf_console_ms;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_DCONSOLE_POLL):
- brcmf_console_ms = (uint) int_val;
- break;
-
- case IOV_SVAL(IOV_CONS):
- if (len > 0)
- bcmerror = brcmf_sdbrcm_bus_console_in(bus->drvr,
- arg, len - 1);
- break;
-
- case IOV_GVAL(IOV_SDREG):
- {
- struct brcmf_sdreg *sd_ptr;
- u32 addr, size;
-
- sd_ptr = (struct brcmf_sdreg *) params;
-
- addr = bus->ci->buscorebase + sd_ptr->offset;
- size = sd_ptr->func;
- int_val = (s32) brcmf_sdcard_reg_read(bus->card, addr,
- size);
- if (brcmf_sdcard_regfail(bus->card))
- bcmerror = -EIO;
- memcpy(arg, &int_val, sizeof(s32));
- break;
- }
-
- case IOV_SVAL(IOV_SDREG):
- {
- struct brcmf_sdreg *sd_ptr;
- u32 addr, size;
-
- sd_ptr = (struct brcmf_sdreg *) params;
-
- addr = bus->ci->buscorebase + sd_ptr->offset;
- size = sd_ptr->func;
- brcmf_sdcard_reg_write(bus->card, addr, size,
- sd_ptr->value);
- if (brcmf_sdcard_regfail(bus->card))
- bcmerror = -EIO;
- break;
- }
-
- /* Same as above, but offset is not backplane
- (not SDIO core) */
- case IOV_GVAL(IOV_SBREG):
- {
- struct brcmf_sdreg sdreg;
- u32 addr, size;
-
- memcpy(&sdreg, params, sizeof(sdreg));
-
- addr = SI_ENUM_BASE + sdreg.offset;
- size = sdreg.func;
- int_val = (s32) brcmf_sdcard_reg_read(bus->card, addr,
- size);
- if (brcmf_sdcard_regfail(bus->card))
- bcmerror = -EIO;
- memcpy(arg, &int_val, sizeof(s32));
- break;
- }
-
- case IOV_SVAL(IOV_SBREG):
- {
- struct brcmf_sdreg sdreg;
- u32 addr, size;
-
- memcpy(&sdreg, params, sizeof(sdreg));
-
- addr = SI_ENUM_BASE + sdreg.offset;
- size = sdreg.func;
- brcmf_sdcard_reg_write(bus->card, addr, size,
- sdreg.value);
- if (brcmf_sdcard_regfail(bus->card))
- bcmerror = -EIO;
- break;
- }
-
- case IOV_GVAL(IOV_SDCIS):
- {
- *(char *)arg = 0;
-
- strcat(arg, "\nFunc 0\n");
- brcmf_sdcard_cis_read(bus->card, 0x10,
- (u8 *) arg + strlen(arg),
- SBSDIO_CIS_SIZE_LIMIT);
- strcat(arg, "\nFunc 1\n");
- brcmf_sdcard_cis_read(bus->card, 0x11,
- (u8 *) arg + strlen(arg),
- SBSDIO_CIS_SIZE_LIMIT);
- strcat(arg, "\nFunc 2\n");
- brcmf_sdcard_cis_read(bus->card, 0x12,
- (u8 *) arg + strlen(arg),
- SBSDIO_CIS_SIZE_LIMIT);
- break;
- }
-
- case IOV_GVAL(IOV_FORCEEVEN):
- int_val = (s32) forcealign;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_FORCEEVEN):
- forcealign = bool_val;
- break;
-
- case IOV_GVAL(IOV_TXBOUND):
- int_val = (s32) brcmf_txbound;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_TXBOUND):
- brcmf_txbound = (uint) int_val;
- break;
-
- case IOV_GVAL(IOV_RXBOUND):
- int_val = (s32) brcmf_rxbound;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_RXBOUND):
- brcmf_rxbound = (uint) int_val;
- break;
-
- case IOV_GVAL(IOV_TXMINMAX):
- int_val = (s32) brcmf_txminmax;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_TXMINMAX):
- brcmf_txminmax = (uint) int_val;
- break;
-#endif /* BCMDBG */
-
-#ifdef SDTEST
- case IOV_GVAL(IOV_EXTLOOP):
- int_val = (s32) bus->ext_loop;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_EXTLOOP):
- bus->ext_loop = bool_val;
- break;
-
- case IOV_GVAL(IOV_PKTGEN):
- bcmerror = brcmf_sdbrcm_pktgen_get(bus, arg);
- break;
-
- case IOV_SVAL(IOV_PKTGEN):
- bcmerror = brcmf_sdbrcm_pktgen_set(bus, arg);
- break;
-#endif /* SDTEST */
-
- case IOV_SVAL(IOV_DEVRESET):
- BRCMF_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d "
- "busstate=%d\n",
- __func__, bool_val, bus->drvr->dongle_reset,
- bus->drvr->busstate));
-
- brcmf_bus_devreset(bus->drvr, (u8) bool_val);
-
- break;
-
- case IOV_GVAL(IOV_DEVRESET):
- BRCMF_TRACE(("%s: Called get IOV_DEVRESET\n", __func__));
-
- /* Get its status */
- int_val = (bool) bus->drvr->dongle_reset;
- memcpy(arg, &int_val, val_size);
-
- break;
-
- case IOV_GVAL(IOV_WDTICK):
- int_val = (s32) brcmf_watchdog_ms;
- memcpy(arg, &int_val, val_size);
- break;
-
- case IOV_SVAL(IOV_WDTICK):
- if (!bus->drvr->up) {
- bcmerror = -ENOLINK;
- break;
- }
- brcmf_sdbrcm_wd_timer(bus, (uint) int_val);
- break;
-
- default:
- bcmerror = -ENOTSUPP;
- break;
+ brcmf_dbg(INFO, "Dongle ready, protocol version %d\n",
+ bus->sdpcm_ver);
}
-exit:
- if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
- }
-
- brcmf_sdbrcm_sdunlock(bus);
-
- if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == false)
- brcmf_c_preinit_ioctls(bus->drvr);
-
- return bcmerror;
-}
-
-static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
-{
- int bcmerror = 0;
- u32 varsize;
- u32 varaddr;
- u8 *vbuffer;
- u32 varsizew;
-#ifdef BCMDBG
- char *nvram_ularray;
-#endif /* BCMDBG */
-
- /* Even if there are no vars are to be written, we still
- need to set the ramsize. */
- varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
- varaddr = (bus->ramsize - 4) - varsize;
-
- if (bus->vars) {
- vbuffer = kzalloc(varsize, GFP_ATOMIC);
- if (!vbuffer)
- return -ENOMEM;
-
- memcpy(vbuffer, bus->vars, bus->varsz);
-
- /* Write the vars list */
- bcmerror =
- brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
-#ifdef BCMDBG
- /* Verify NVRAM bytes */
- BRCMF_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
- nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
- if (!nvram_ularray)
- return -ENOMEM;
-
- /* Upload image to verify downloaded contents. */
- memset(nvram_ularray, 0xaa, varsize);
-
- /* Read the vars list to temp buffer for comparison */
- bcmerror =
- brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
- varsize);
- if (bcmerror) {
- BRCMF_ERROR(("%s: error %d on reading %d nvram bytes"
- " at 0x%08x\n", __func__, bcmerror,
- varsize, varaddr));
- }
- /* Compare the org NVRAM with the one read from RAM */
- if (memcmp(vbuffer, nvram_ularray, varsize)) {
- BRCMF_ERROR(("%s: Downloaded NVRAM image is "
- "corrupted.\n", __func__));
- } else
- BRCMF_ERROR(("%s: Download/Upload/Compare of"
- " NVRAM ok.\n", __func__));
-
- kfree(nvram_ularray);
-#endif /* BCMDBG */
-
- kfree(vbuffer);
- }
-
- /* adjust to the user specified RAM */
- BRCMF_INFO(("Physical memory size: %d, usable memory size: %d\n",
- bus->orig_ramsize, bus->ramsize));
- BRCMF_INFO(("Vars are at %d, orig varsize is %d\n", varaddr, varsize));
- varsize = ((bus->orig_ramsize - 4) - varaddr);
-
/*
- * Determine the length token:
- * Varsize, converted to words, in lower 16-bits, checksum
- * in upper 16-bits.
- */
- if (bcmerror) {
- varsizew = 0;
- } else {
- varsizew = varsize / 4;
- varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
- varsizew = cpu_to_le32(varsizew);
- }
-
- BRCMF_INFO(("New varsize is %d, length token=0x%08x\n", varsize,
- varsizew));
-
- /* Write the length token to the last word */
- bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->orig_ramsize - 4),
- (u8 *)&varsizew, 4);
-
- return bcmerror;
-}
-
-static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
-{
- uint retries;
- u32 regdata;
- int bcmerror = 0;
-
- /* To enter download state, disable ARM and reset SOCRAM.
- * To exit download state, simply reset ARM (default is RAM boot).
- */
- if (enter) {
- bus->alp_only = true;
-
- brcmf_sdbrcm_chip_disablecore(bus->card, bus->ci->armcorebase);
-
- brcmf_sdbrcm_chip_resetcore(bus->card, bus->ci->ramcorebase);
-
- /* Clear the top bit of memory */
- if (bus->ramsize) {
- u32 zeros = 0;
- brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
- (u8 *)&zeros, 4);
- }
- } else {
- regdata = brcmf_sdcard_reg_read(bus->card,
- CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
- regdata &= (SBTML_RESET | SBTML_REJ_MASK |
- (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
- if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
- BRCMF_ERROR(("%s: SOCRAM core is down after reset?\n",
- __func__));
- bcmerror = -EBADE;
- goto fail;
- }
-
- bcmerror = brcmf_sdbrcm_write_vars(bus);
- if (bcmerror) {
- BRCMF_ERROR(("%s: no vars written to RAM\n", __func__));
- bcmerror = 0;
- }
-
- w_sdreg32(bus, 0xFFFFFFFF,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
-
- brcmf_sdbrcm_chip_resetcore(bus->card, bus->ci->armcorebase);
-
- /* Allow HT Clock now that the ARM is running. */
- bus->alp_only = false;
-
- bus->drvr->busstate = BRCMF_BUS_LOAD;
- }
-fail:
- return bcmerror;
-}
-
-int
-brcmf_sdbrcm_bus_iovar_op(struct brcmf_pub *drvr, const char *name,
- void *params, int plen, void *arg, int len, bool set)
-{
- struct brcmf_bus *bus = drvr->bus;
- const struct brcmu_iovar *vi = NULL;
- int bcmerror = 0;
- int val_size;
- u32 actionid;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (name == NULL || len <= 0)
- return -EINVAL;
-
- /* Set does not take qualifiers */
- if (set && (params || plen))
- return -EINVAL;
-
- /* Get must have return space;*/
- if (!set && !(arg && len))
- return -EINVAL;
-
- /* Look up var locally; if not found pass to host driver */
- vi = brcmu_iovar_lookup(brcmf_sdio_iovars, name);
- if (vi == NULL) {
- brcmf_sdbrcm_sdlock(bus);
-
- BUS_WAKE(bus);
-
- /* Turn on clock in case SD command needs backplane */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
-
- bcmerror = brcmf_sdcard_iovar_op(bus->card, name, params, plen,
- arg, len, set);
-
- /* Similar check for blocksize change */
- if (set && strcmp(name, "sd_blocksize") == 0) {
- s32 fnum = 2;
- if (brcmf_sdcard_iovar_op
- (bus->card, "sd_blocksize", &fnum, sizeof(s32),
- &bus->blocksize, sizeof(s32),
- false) != 0) {
- bus->blocksize = 0;
- BRCMF_ERROR(("%s: fail on %s get\n", __func__,
- "sd_blocksize"));
- } else {
- BRCMF_INFO(("%s: noted sd_blocksize update,"
- " value now %d\n", __func__,
- bus->blocksize));
- }
- }
- bus->roundup = min(max_roundup, bus->blocksize);
-
- if (bus->idletime == BRCMF_IDLE_IMMEDIATE &&
- !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
- }
-
- brcmf_sdbrcm_sdunlock(bus);
- goto exit;
- }
-
- BRCMF_CTL(("%s: %s %s, len %d plen %d\n", __func__,
- name, (set ? "set" : "get"), len, plen));
-
- /* set up 'params' pointer in case this is a set command so that
- * the convenience int and bool code can be common to set and get
+ * Flow Control has been moved into the RX headers and this out of band
+ * method isn't used any more.
+ * remaining backward compatible with older dongles.
*/
- if (params == NULL) {
- params = arg;
- plen = len;
- }
-
- if (vi->type == IOVT_VOID)
- val_size = 0;
- else if (vi->type == IOVT_BUFFER)
- val_size = len;
- else
- /* all other types are integer sized */
- val_size = sizeof(int);
-
- actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
- bcmerror = brcmf_sdbrcm_doiovar(bus, vi, actionid, name, params, plen,
- arg, len, val_size);
-
-exit:
- return bcmerror;
-}
-
-void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus, bool enforce_mutex)
-{
- u32 local_hostintmask;
- u8 saveclk;
- uint retries;
- int err;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (enforce_mutex)
- brcmf_sdbrcm_sdlock(bus);
-
- BUS_WAKE(bus);
-
- /* Enable clock for device interrupts */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
-
- if (bus->watchdog_tsk) {
- send_sig(SIGTERM, bus->watchdog_tsk, 1);
- kthread_stop(bus->watchdog_tsk);
- bus->watchdog_tsk = NULL;
- }
-
- if (bus->dpc_tsk) {
- send_sig(SIGTERM, bus->dpc_tsk, 1);
- kthread_stop(bus->dpc_tsk);
- bus->dpc_tsk = NULL;
- } else
- tasklet_kill(&bus->tasklet);
-
- /* Disable and clear interrupts at the chip level also */
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
- local_hostintmask = bus->hostintmask;
- bus->hostintmask = 0;
-
- /* Change our idea of bus state */
- bus->drvr->busstate = BRCMF_BUS_DOWN;
-
- /* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (!err) {
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
- }
- if (err) {
- BRCMF_ERROR(("%s: Failed to force clock for F2: err %d\n",
- __func__, err));
- }
-
- /* Turn off the bus (F2), free any pending packets */
- BRCMF_INTR(("%s: disable SDIO interrupts\n", __func__));
- brcmf_sdcard_intr_disable(bus->card);
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
-
- /* Clear any pending interrupts now that F2 is disabled */
- w_sdreg32(bus, local_hostintmask,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
-
- /* Turn off the backplane clock (only) */
- brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
-
- /* Clear the data packet queues */
- brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
-
- /* Clear any held glomming stuff */
- if (bus->glomd)
- brcmu_pkt_buf_free_skb(bus->glomd);
-
- if (bus->glom)
- brcmu_pkt_buf_free_skb(bus->glom);
-
- bus->glom = bus->glomd = NULL;
-
- /* Clear rx control and wake any waiters */
- bus->rxlen = 0;
- brcmf_os_ioctl_resp_wake(bus->drvr);
-
- /* Reset some F2 state stuff */
- bus->rxskip = false;
- bus->tx_seq = bus->rx_seq = 0;
-
- if (enforce_mutex)
- brcmf_sdbrcm_sdunlock(bus);
-}
-
-int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr, bool enforce_mutex)
-{
- struct brcmf_bus *bus = drvr->bus;
- struct brcmf_timeout tmo;
- uint retries = 0;
- u8 ready, enable;
- int err, ret = 0;
- u8 saveclk;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- /* try to download image and nvram to the dongle */
- if (drvr->busstate == BRCMF_BUS_DOWN) {
- if (!(brcmf_sdbrcm_download_firmware(bus, bus->card)))
- return -1;
- }
-
- if (!bus->drvr)
- return 0;
-
- /* Start the watchdog timer */
- bus->drvr->tickcnt = 0;
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
-
- if (enforce_mutex)
- brcmf_sdbrcm_sdlock(bus);
-
- /* Make sure backplane clock is on, needed to generate F2 interrupt */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- if (bus->clkstate != CLK_AVAIL)
- goto exit;
-
- /* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk =
- brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
- if (!err) {
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
- }
- if (err) {
- BRCMF_ERROR(("%s: Failed to force clock for F2: err %d\n",
- __func__, err));
- goto exit;
- }
-
- /* Enable function 2 (frame transfers) */
- w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
- offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
- enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
-
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx, enable,
- NULL);
-
- /* Give the dongle some time to do its thing and set IOR2 */
- brcmf_timeout_start(&tmo, BRCMF_WAIT_F2RDY * 1000);
-
- ready = 0;
- while (ready != enable && !brcmf_timeout_expired(&tmo))
- ready = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_0,
- SDIO_CCCR_IORx, NULL);
-
- BRCMF_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
- __func__, enable, ready, tmo.elapsed));
-
- /* If F2 successfully enabled, set core and enable interrupts */
- if (ready == enable) {
- /* Set up the interrupt mask and enable interrupts */
- bus->hostintmask = HOSTINTMASK;
- w_sdreg32(bus, bus->hostintmask,
- offsetof(struct sdpcmd_regs, hostintmask), &retries);
-
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_WATERMARK,
- (u8) watermark, &err);
-
- /* Set bus state according to enable result */
- drvr->busstate = BRCMF_BUS_DATA;
-
- bus->intdis = false;
- if (bus->intr) {
- BRCMF_INTR(("%s: enable SDIO device interrupts\n",
- __func__));
- brcmf_sdcard_intr_enable(bus->card);
- } else {
- BRCMF_INTR(("%s: disable SDIO interrupts\n", __func__));
- brcmf_sdcard_intr_disable(bus->card);
- }
-
- }
+ if (hmb_data & HMB_DATA_FC) {
+ fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
+ HMB_DATA_FCDATA_SHIFT;
- else {
- /* Disable F2 again */
- enable = SDIO_FUNC_ENABLE_1;
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- enable, NULL);
- }
+ if (fcbits & ~bus->flowcontrol)
+ bus->fc_xoff++;
- /* Restore previous clock setting */
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
- saveclk, &err);
+ if (bus->flowcontrol & ~fcbits)
+ bus->fc_xon++;
-#if defined(OOB_INTR_ONLY)
- /* Host registration for OOB interrupt */
- if (brcmf_sdio_register_oob_intr(bus->dhd)) {
- brcmf_sdbrcm_wd_timer(bus, 0);
- BRCMF_ERROR(("%s Host failed to resgister for OOB\n",
- __func__));
- ret = -ENODEV;
- goto exit;
+ bus->fc_rcvd++;
+ bus->flowcontrol = fcbits;
}
- /* Enable oob at firmware */
- brcmf_sdbrcm_enable_oob_intr(bus, true);
-#endif /* defined(OOB_INTR_ONLY) */
-
- /* If we didn't come up, turn off backplane clock */
- if (drvr->busstate != BRCMF_BUS_DATA)
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
-
-exit:
- if (enforce_mutex)
- brcmf_sdbrcm_sdunlock(bus);
+ /* Shouldn't be any others */
+ if (hmb_data & ~(HMB_DATA_DEVREADY |
+ HMB_DATA_NAKHANDLED |
+ HMB_DATA_FC |
+ HMB_DATA_FWREADY |
+ HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK))
+ brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n",
+ hmb_data);
- return ret;
+ return intstatus;
}
static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
{
- struct brcmf_sdio_card *card = bus->card;
uint retries = 0;
u16 lastrbc;
u8 hi, lo;
int err;
- BRCMF_ERROR(("%s: %sterminate frame%s\n", __func__,
- (abort ? "abort command, " : ""),
- (rtx ? ", send NAK" : "")));
+ brcmf_dbg(ERROR, "%sterminate frame%s\n",
+ abort ? "abort command, " : "",
+ rtx ? ", send NAK" : "");
if (abort)
- brcmf_sdcard_abort(card, SDIO_FUNC_2);
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL,
SFC_RF_TERM, &err);
bus->f1regdata++;
/* Wait until the packet has been flushed (device/FIFO stable) */
for (lastrbc = retries = 0xffff; retries > 0; retries--) {
- hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_RFRAMEBCHI, NULL);
- lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_RFRAMEBCLO, NULL);
bus->f1regdata += 2;
@@ -3448,20 +1193,16 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
break;
if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
- BRCMF_ERROR(("%s: count growing: last 0x%04x now "
- "0x%04x\n",
- __func__, lastrbc, ((hi << 8) + lo)));
+ brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n",
+ lastrbc, (hi << 8) + lo);
}
lastrbc = (hi << 8) + lo;
}
- if (!retries) {
- BRCMF_ERROR(("%s: count never zeroed: last 0x%04x\n",
- __func__, lastrbc));
- } else {
- BRCMF_INFO(("%s: flush took %d iterations\n", __func__,
- (0xffff - retries)));
- }
+ if (!retries)
+ brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc);
+ else
+ brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries);
if (rtx) {
bus->rxrtx++;
@@ -3477,113 +1218,10 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
bus->nextlen = 0;
/* If we can't reach the device, signal failure */
- if (err || brcmf_sdcard_regfail(card))
+ if (err || brcmf_sdcard_regfail(bus->sdiodev))
bus->drvr->busstate = BRCMF_BUS_DOWN;
}
-static void
-brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
-{
- struct brcmf_sdio_card *card = bus->card;
- uint rdlen, pad;
-
- int sdret;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- /* Control data already received in aligned rxctl */
- if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
- goto gotpkt;
-
- /* Set rxctl for frame (w/optional alignment) */
- bus->rxctl = bus->rxbuf;
- if (brcmf_alignctl) {
- bus->rxctl += firstread;
- pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
- if (pad)
- bus->rxctl += (BRCMF_SDALIGN - pad);
- bus->rxctl -= firstread;
- }
-
- /* Copy the already-read portion over */
- memcpy(bus->rxctl, hdr, firstread);
- if (len <= firstread)
- goto gotpkt;
-
- /* Copy the full data pkt in gSPI case and process ioctl. */
- if (bus->bus == SPI_BUS) {
- memcpy(bus->rxctl, hdr, len);
- goto gotpkt;
- }
-
- /* Raise rdlen to next SDIO block to avoid tail command */
- rdlen = len - firstread;
- if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
- pad = bus->blocksize - (rdlen % bus->blocksize);
- if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
- ((len + pad) < bus->drvr->maxctl))
- rdlen += pad;
- } else if (rdlen % BRCMF_SDALIGN) {
- rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
- }
-
- /* Satisfy length-alignment requirements */
- if (forcealign && (rdlen & (ALIGNMENT - 1)))
- rdlen = roundup(rdlen, ALIGNMENT);
-
- /* Drop if the read is too big or it exceeds our maximum */
- if ((rdlen + firstread) > bus->drvr->maxctl) {
- BRCMF_ERROR(("%s: %d-byte control read exceeds %d-byte"
- " buffer\n", __func__, rdlen, bus->drvr->maxctl));
- bus->drvr->rx_errors++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- goto done;
- }
-
- if ((len - doff) > bus->drvr->maxctl) {
- BRCMF_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds "
- "%d-byte limit\n",
- __func__, len, (len - doff), bus->drvr->maxctl));
- bus->drvr->rx_errors++;
- bus->rx_toolong++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- goto done;
- }
-
- /* Read remainder of frame body into the rxctl buffer */
- sdret = brcmf_sdcard_recv_buf(card, brcmf_sdcard_cur_sbwad(card),
- SDIO_FUNC_2,
- F2SYNC, (bus->rxctl + firstread), rdlen,
- NULL, NULL, NULL);
- bus->f2rxdata++;
-
- /* Control frame failures need retransmission */
- if (sdret < 0) {
- BRCMF_ERROR(("%s: read %d control bytes failed: %d\n",
- __func__, rdlen, sdret));
- bus->rxc_errors++;
- brcmf_sdbrcm_rxfail(bus, true, true);
- goto done;
- }
-
-gotpkt:
-
-#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
- printk(KERN_DEBUG "RxCtrl:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len);
- }
-#endif
-
- /* Point to valid data and indicate its length */
- bus->rxctl += doff;
- bus->rxlen = len - doff;
-
-done:
- /* Awake any waiters */
- brcmf_os_ioctl_resp_wake(bus->drvr);
-}
-
static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
{
u16 dlen, totlen;
@@ -3602,8 +1240,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
/* If packets, issue read(s) and send up packet chain */
/* Return sequence numbers consumed? */
- BRCMF_TRACE(("brcmf_sdbrcm_rxglom: start: glomd %p glom %p\n",
- bus->glomd, bus->glom));
+ brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);
/* If there's a descriptor, generate the packet chain */
if (bus->glomd) {
@@ -3611,9 +1248,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
dlen = (u16) (bus->glomd->len);
dptr = bus->glomd->data;
if (!dlen || (dlen & 1)) {
- BRCMF_ERROR(("%s: bad glomd len(%d),"
- " ignore descriptor\n",
- __func__, dlen));
+ brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n",
+ dlen);
dlen = 0;
}
@@ -3624,15 +1260,14 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
dptr += sizeof(u16);
if ((sublen < SDPCM_HDRLEN) ||
((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
- BRCMF_ERROR(("%s: descriptor len %d bad: %d\n",
- __func__, num, sublen));
+ brcmf_dbg(ERROR, "descriptor len %d bad: %d\n",
+ num, sublen);
pnext = NULL;
break;
}
if (sublen % BRCMF_SDALIGN) {
- BRCMF_ERROR(("%s: sublen %d not multiple of"
- " %d\n", __func__, sublen,
- BRCMF_SDALIGN));
+ brcmf_dbg(ERROR, "sublen %d not multiple of %d\n",
+ sublen, BRCMF_SDALIGN);
usechain = false;
}
totlen += sublen;
@@ -3648,9 +1283,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
/* Allocate/chain packet for next subframe */
pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN);
if (pnext == NULL) {
- BRCMF_ERROR(("%s: bcm_pkt_buf_get_skb failed, "
- "num %d len %d\n", __func__,
- num, sublen));
+ brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n",
+ num, sublen);
break;
}
if (!pfirst) {
@@ -3661,22 +1295,18 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
}
/* Adhere to start alignment requirements */
- PKTALIGN(pnext, sublen, BRCMF_SDALIGN);
+ pkt_align(pnext, sublen, BRCMF_SDALIGN);
}
/* If all allocations succeeded, save packet chain
in bus structure */
if (pnext) {
- BRCMF_GLOM(("%s: allocated %d-byte packet chain for %d "
- "subframes\n", __func__, totlen, num));
- if (BRCMF_GLOM_ON() && bus->nextlen) {
- if (totlen != bus->nextlen) {
- BRCMF_GLOM(("%s: glomdesc mismatch: "
- "nextlen %d glomdesc %d "
- "rxseq %d\n", __func__,
- bus->nextlen,
- totlen, rxseq));
- }
+ brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n",
+ totlen, num);
+ if (BRCMF_GLOM_ON() && bus->nextlen &&
+ totlen != bus->nextlen) {
+ brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
+ bus->nextlen, totlen, rxseq);
}
bus->glom = pfirst;
pfirst = pnext = NULL;
@@ -3697,12 +1327,11 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
or had one from before */
if (bus->glom) {
if (BRCMF_GLOM_ON()) {
- BRCMF_GLOM(("%s: try superframe read, packet chain:\n",
- __func__));
+ brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
for (pnext = bus->glom; pnext; pnext = pnext->next) {
- BRCMF_GLOM((" %p: %p len 0x%04x (%d)\n",
- pnext, (u8 *) (pnext->data),
- pnext->len, pnext->len));
+ brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n",
+ pnext, (u8 *) (pnext->data),
+ pnext->len, pnext->len);
}
}
@@ -3714,37 +1343,36 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
* packet and and copy into the chain.
*/
if (usechain) {
- errcode = brcmf_sdcard_recv_buf(bus->card,
- brcmf_sdcard_cur_sbwad(bus->card),
+ errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
SDIO_FUNC_2,
F2SYNC, (u8 *) pfirst->data, dlen,
- pfirst, NULL, NULL);
+ pfirst);
} else if (bus->dataptr) {
- errcode = brcmf_sdcard_recv_buf(bus->card,
- brcmf_sdcard_cur_sbwad(bus->card),
+ errcode = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
SDIO_FUNC_2,
F2SYNC, bus->dataptr, dlen,
- NULL, NULL, NULL);
+ NULL);
sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
bus->dataptr);
if (sublen != dlen) {
- BRCMF_ERROR(("%s: FAILED TO COPY, dlen %d "
- "sublen %d\n",
- __func__, dlen, sublen));
+ brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
+ dlen, sublen);
errcode = -1;
}
pnext = NULL;
} else {
- BRCMF_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, "
- "FORCE FAILURE\n", dlen));
+ brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n",
+ dlen);
errcode = -1;
}
bus->f2rxdata++;
/* On failure, kill the superframe, allow a couple retries */
if (errcode < 0) {
- BRCMF_ERROR(("%s: glom read of %d bytes failed: %d\n",
- __func__, dlen, errcode));
+ brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n",
+ dlen, errcode);
bus->drvr->rx_errors++;
if (bus->glomerr++ < 3) {
@@ -3775,8 +1403,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
- BRCMF_INFO(("%s: nextlen too large (%d) seq %d\n",
- __func__, bus->nextlen, seq));
+ brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n",
+ bus->nextlen, seq);
bus->nextlen = 0;
}
doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
@@ -3784,48 +1412,42 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
errcode = 0;
if ((u16)~(sublen ^ check)) {
- BRCMF_ERROR(("%s (superframe): HW hdr error: len/check "
- "0x%04x/0x%04x\n", __func__, sublen,
- check));
+ brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
+ sublen, check);
errcode = -1;
} else if (roundup(sublen, bus->blocksize) != dlen) {
- BRCMF_ERROR(("%s (superframe): len 0x%04x, rounded "
- "0x%04x, expect 0x%04x\n",
- __func__, sublen,
- roundup(sublen, bus->blocksize), dlen));
+ brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
+ sublen, roundup(sublen, bus->blocksize),
+ dlen);
errcode = -1;
} else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) !=
SDPCM_GLOM_CHANNEL) {
- BRCMF_ERROR(("%s (superframe): bad channel %d\n",
- __func__,
- SDPCM_PACKET_CHANNEL(&dptr
- [SDPCM_FRAMETAG_LEN])));
+ brcmf_dbg(ERROR, "(superframe): bad channel %d\n",
+ SDPCM_PACKET_CHANNEL(
+ &dptr[SDPCM_FRAMETAG_LEN]));
errcode = -1;
} else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
- BRCMF_ERROR(("%s (superframe): got 2nd descriptor?\n",
- __func__));
+ brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n");
errcode = -1;
} else if ((doff < SDPCM_HDRLEN) ||
(doff > (pfirst->len - SDPCM_HDRLEN))) {
- BRCMF_ERROR(("%s (superframe): Bad data offset %d: "
- "HW %d pkt %d min %d\n",
- __func__, doff, sublen,
- pfirst->len, SDPCM_HDRLEN));
+ brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n",
+ doff, sublen, pfirst->len, SDPCM_HDRLEN);
errcode = -1;
}
/* Check sequence number of superframe SW header */
if (rxseq != seq) {
- BRCMF_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
- __func__, seq, rxseq));
+ brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n",
+ seq, rxseq);
bus->rx_badseq++;
rxseq = seq;
}
/* Check window for sanity */
if ((u8) (txmax - bus->tx_seq) > 0x40) {
- BRCMF_ERROR(("%s: unlikely tx max %d with tx_seq %d\n",
- __func__, txmax, bus->tx_seq));
+ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
txmax = bus->tx_seq + 2;
}
bus->tx_max = txmax;
@@ -3852,25 +1474,21 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
#endif
if ((u16)~(sublen ^ check)) {
- BRCMF_ERROR(("%s (subframe %d): HW hdr error: "
- "len/check 0x%04x/0x%04x\n",
- __func__, num, sublen, check));
+ brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n",
+ num, sublen, check);
errcode = -1;
} else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
- BRCMF_ERROR(("%s (subframe %d): length mismatch"
- ": len 0x%04x, expect 0x%04x\n",
- __func__, num, sublen, dlen));
+ brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n",
+ num, sublen, dlen);
errcode = -1;
} else if ((chan != SDPCM_DATA_CHANNEL) &&
(chan != SDPCM_EVENT_CHANNEL)) {
- BRCMF_ERROR(("%s (subframe %d): bad channel"
- " %d\n", __func__, num, chan));
+ brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n",
+ num, chan);
errcode = -1;
} else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
- BRCMF_ERROR(("%s (subframe %d): Bad data offset"
- " %d: HW %d min %d\n",
- __func__, num, doff, sublen,
- SDPCM_HDRLEN));
+ brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n",
+ num, doff, sublen, SDPCM_HDRLEN);
errcode = -1;
}
}
@@ -3908,17 +1526,16 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
- BRCMF_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d "
- "chan %d seq %d\n",
- __func__, num, pfirst, pfirst->data,
- pfirst->len, sublen, chan, seq));
+ brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
+ num, pfirst, pfirst->data,
+ pfirst->len, sublen, chan, seq);
/* precondition: chan == SDPCM_DATA_CHANNEL ||
chan == SDPCM_EVENT_CHANNEL */
if (rxseq != seq) {
- BRCMF_GLOM(("%s: rx_seq %d, expected %d\n",
- __func__, seq, rxseq));
+ brcmf_dbg(GLOM, "rx_seq %d, expected %d\n",
+ seq, rxseq);
bus->rx_badseq++;
rxseq = seq;
}
@@ -3935,23 +1552,22 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
if (pfirst->len == 0) {
brcmu_pkt_buf_free_skb(pfirst);
- if (plast) {
+ if (plast)
plast->next = pnext;
- } else {
+ else
save_pfirst = pnext;
- }
+
continue;
- } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pfirst)
- != 0) {
- BRCMF_ERROR(("%s: rx protocol error\n",
- __func__));
+ } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx,
+ pfirst) != 0) {
+ brcmf_dbg(ERROR, "rx protocol error\n");
bus->drvr->rx_errors++;
brcmu_pkt_buf_free_skb(pfirst);
- if (plast) {
+ if (plast)
plast->next = pnext;
- } else {
+ else
save_pfirst = pnext;
- }
+
continue;
}
@@ -3963,11 +1579,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
#ifdef BCMDBG
if (BRCMF_GLOM_ON()) {
- BRCMF_GLOM(("%s subframe %d to stack, %p"
- "(%p/%d) nxt/lnk %p/%p\n",
- __func__, num, pfirst, pfirst->data,
- pfirst->len, pfirst->next,
- pfirst->prev));
+ brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n",
+ num, pfirst, pfirst->data,
+ pfirst->len, pfirst->next,
+ pfirst->prev);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
pfirst->data,
min_t(int, pfirst->len, 32));
@@ -3975,9 +1590,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
#endif /* BCMDBG */
}
if (num) {
- brcmf_sdbrcm_sdunlock(bus);
+ up(&bus->sdsem);
brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num);
- brcmf_sdbrcm_sdlock(bus);
+ down(&bus->sdsem);
}
bus->rxglomframes++;
@@ -3986,12 +1601,230 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
return num;
}
+static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition,
+ bool *pending)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT);
+
+ /* Wait until control frame is available */
+ add_wait_queue(&bus->dcmd_resp_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (!(*condition) && (!signal_pending(current) && timeout))
+ timeout = schedule_timeout(timeout);
+
+ if (signal_pending(current))
+ *pending = true;
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&bus->dcmd_resp_wait, &wait);
+
+ return timeout;
+}
+
+static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus)
+{
+ if (waitqueue_active(&bus->dcmd_resp_wait))
+ wake_up_interruptible(&bus->dcmd_resp_wait);
+
+ return 0;
+}
+static void
+brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff)
+{
+ uint rdlen, pad;
+
+ int sdret;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Set rxctl for frame (w/optional alignment) */
+ bus->rxctl = bus->rxbuf;
+ bus->rxctl += BRCMF_FIRSTREAD;
+ pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
+ if (pad)
+ bus->rxctl += (BRCMF_SDALIGN - pad);
+ bus->rxctl -= BRCMF_FIRSTREAD;
+
+ /* Copy the already-read portion over */
+ memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD);
+ if (len <= BRCMF_FIRSTREAD)
+ goto gotpkt;
+
+ /* Raise rdlen to next SDIO block to avoid tail command */
+ rdlen = len - BRCMF_FIRSTREAD;
+ if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
+ pad = bus->blocksize - (rdlen % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
+ ((len + pad) < bus->drvr->maxctl))
+ rdlen += pad;
+ } else if (rdlen % BRCMF_SDALIGN) {
+ rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
+ }
+
+ /* Satisfy length-alignment requirements */
+ if (rdlen & (ALIGNMENT - 1))
+ rdlen = roundup(rdlen, ALIGNMENT);
+
+ /* Drop if the read is too big or it exceeds our maximum */
+ if ((rdlen + BRCMF_FIRSTREAD) > bus->drvr->maxctl) {
+ brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n",
+ rdlen, bus->drvr->maxctl);
+ bus->drvr->rx_errors++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto done;
+ }
+
+ if ((len - doff) > bus->drvr->maxctl) {
+ brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
+ len, len - doff, bus->drvr->maxctl);
+ bus->drvr->rx_errors++;
+ bus->rx_toolong++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto done;
+ }
+
+ /* Read remainder of frame body into the rxctl buffer */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
+ bus->sdiodev->sbwad,
+ SDIO_FUNC_2,
+ F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen,
+ NULL);
+ bus->f2rxdata++;
+
+ /* Control frame failures need retransmission */
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "read %d control bytes failed: %d\n",
+ rdlen, sdret);
+ bus->rxc_errors++;
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ goto done;
+ }
+
+gotpkt:
+
+#ifdef BCMDBG
+ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
+ printk(KERN_DEBUG "RxCtrl:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len);
+ }
+#endif
+
+ /* Point to valid data and indicate its length */
+ bus->rxctl += doff;
+ bus->rxlen = len - doff;
+
+done:
+ /* Awake any waiters */
+ brcmf_sdbrcm_dcmd_resp_wake(bus);
+}
+
+/* Pad read to blocksize for efficiency */
+static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen)
+{
+ if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) {
+ *pad = bus->blocksize - (*rdlen % bus->blocksize);
+ if (*pad <= bus->roundup && *pad < bus->blocksize &&
+ *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ)
+ *rdlen += *pad;
+ } else if (*rdlen % BRCMF_SDALIGN) {
+ *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN);
+ }
+}
+
+static void
+brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen,
+ struct sk_buff **pkt, u8 **rxbuf)
+{
+ int sdret; /* Return code from calls */
+
+ *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN);
+ if (*pkt == NULL)
+ return;
+
+ pkt_align(*pkt, rdlen, BRCMF_SDALIGN);
+ *rxbuf = (u8 *) ((*pkt)->data);
+ /* Read the entire frame */
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC,
+ *rxbuf, rdlen, *pkt);
+ bus->f2rxdata++;
+
+ if (sdret < 0) {
+ brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n",
+ rdlen, sdret);
+ brcmu_pkt_buf_free_skb(*pkt);
+ bus->drvr->rx_errors++;
+ /* Force retry w/normal header read.
+ * Don't attempt NAK for
+ * gSPI
+ */
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ *pkt = NULL;
+ }
+}
+
+/* Checks the header */
+static int
+brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf,
+ u8 rxseq, u16 nextlen, u16 *len)
+{
+ u16 check;
+ bool len_consistent; /* Result of comparing readahead len and
+ len from hw-hdr */
+
+ memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN);
+
+ /* Extract hardware header fields */
+ *len = get_unaligned_le16(bus->rxhdr);
+ check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
+
+ /* All zeros means readahead info was bad */
+ if (!(*len | check)) {
+ brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n");
+ goto fail;
+ }
+
+ /* Validate check bytes */
+ if ((u16)~(*len ^ check)) {
+ brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n",
+ nextlen, *len, check);
+ bus->rx_badhdr++;
+ brcmf_sdbrcm_rxfail(bus, false, false);
+ goto fail;
+ }
+
+ /* Validate frame length */
+ if (*len < SDPCM_HDRLEN) {
+ brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n",
+ *len);
+ goto fail;
+ }
+
+ /* Check for consistency with readahead info */
+ len_consistent = (nextlen != (roundup(*len, 16) >> 4));
+ if (len_consistent) {
+ /* Mismatch, force retry w/normal
+ header (may be >4K) */
+ brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n",
+ nextlen, *len, roundup(*len, 16),
+ rxseq);
+ brcmf_sdbrcm_rxfail(bus, true, true);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ brcmf_sdbrcm_pktfree2(bus, pkt);
+ return -EINVAL;
+}
+
/* Return true if there may be more frames to read */
static uint
brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
{
- struct brcmf_sdio_card *card = bus->card;
-
u16 len, check; /* Extracted hardware header fields */
u8 chan, seq, doff; /* Extracted software header fields */
u8 fcbits; /* Extracted fcbits from software header */
@@ -4003,25 +1836,11 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
uint rxleft = 0; /* Remaining number of frames allowed */
int sdret; /* Return code from calls */
u8 txmax; /* Maximum tx sequence offered */
- bool len_consistent; /* Result of comparing readahead len and
- len from hw-hdr */
u8 *rxbuf;
int ifidx = 0;
uint rxcount = 0; /* Total frames read */
-#if defined(BCMDBG) || defined(SDTEST)
- bool sdtest = false; /* To limit message spew from test mode */
-#endif
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
-#ifdef SDTEST
- /* Allow pktgen to override maxframes */
- if (bus->pktgen_count && (bus->pktgen_mode == BRCMF_PKTGEN_RECV)) {
- maxframes = bus->pktgen_count;
- sdtest = true;
- }
-#endif
+ brcmf_dbg(TRACE, "Enter\n");
/* Not finished unless we encounter no more frames indication */
*finished = false;
@@ -4033,185 +1852,39 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Handle glomming separately */
if (bus->glom || bus->glomd) {
u8 cnt;
- BRCMF_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
- __func__, bus->glomd, bus->glom));
+ brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
+ bus->glomd, bus->glom);
cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
- BRCMF_GLOM(("%s: rxglom returned %d\n", __func__, cnt));
+ brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
rxseq += cnt - 1;
rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
continue;
}
/* Try doing single read if we can */
- if (brcmf_readahead && bus->nextlen) {
+ if (bus->nextlen) {
u16 nextlen = bus->nextlen;
bus->nextlen = 0;
- if (bus->bus == SPI_BUS) {
- rdlen = len = nextlen;
- } else {
- rdlen = len = nextlen << 4;
-
- /* Pad read to blocksize for efficiency */
- if (bus->roundup && bus->blocksize
- && (rdlen > bus->blocksize)) {
- pad =
- bus->blocksize -
- (rdlen % bus->blocksize);
- if ((pad <= bus->roundup)
- && (pad < bus->blocksize)
- && ((rdlen + pad + firstread) <
- MAX_RX_DATASZ))
- rdlen += pad;
- } else if (rdlen % BRCMF_SDALIGN) {
- rdlen +=
- BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
- }
- }
+ rdlen = len = nextlen << 4;
+ brcmf_pad(bus, &pad, &rdlen);
- /* We use bus->rxctl buffer in WinXP for initial
- * control pkt receives.
- * Later we use buffer-poll for data as well
- * as control packets.
- * This is required because dhd receives full
- * frame in gSPI unlike SDIO.
+ /*
* After the frame is received we have to
* distinguish whether it is data
* or non-data frame.
*/
- /* Allocate a packet buffer */
- pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN);
- if (!pkt) {
- if (bus->bus == SPI_BUS) {
- bus->usebufpool = false;
- bus->rxctl = bus->rxbuf;
- if (brcmf_alignctl) {
- bus->rxctl += firstread;
- pad = ((unsigned long)bus->rxctl %
- BRCMF_SDALIGN);
- if (pad)
- bus->rxctl +=
- (BRCMF_SDALIGN - pad);
- bus->rxctl -= firstread;
- }
- rxbuf = bus->rxctl;
- /* Read the entire frame */
- sdret = brcmf_sdcard_recv_buf(card,
- brcmf_sdcard_cur_sbwad(card),
- SDIO_FUNC_2, F2SYNC,
- rxbuf, rdlen,
- NULL, NULL, NULL);
- bus->f2rxdata++;
-
- /* Control frame failures need
- retransmission */
- if (sdret < 0) {
- BRCMF_ERROR(("%s: read %d "
- "control bytes "
- "failed: %d\n",
- __func__,
- rdlen, sdret));
- /* dhd.rx_ctlerrs is higher */
- bus->rxc_errors++;
- brcmf_sdbrcm_rxfail(bus, true,
- (bus->bus ==
- SPI_BUS) ? false
- : true);
- continue;
- }
- } else {
- /* Give up on data,
- request rtx of events */
- BRCMF_ERROR(("%s (nextlen): "
- "brcmu_pkt_buf_get_skb "
- "failed:"
- " len %d rdlen %d expected"
- " rxseq %d\n", __func__,
- len, rdlen, rxseq));
- continue;
- }
- } else {
- if (bus->bus == SPI_BUS)
- bus->usebufpool = true;
-
- PKTALIGN(pkt, rdlen, BRCMF_SDALIGN);
- rxbuf = (u8 *) (pkt->data);
- /* Read the entire frame */
- sdret = brcmf_sdcard_recv_buf(card,
- brcmf_sdcard_cur_sbwad(card),
- SDIO_FUNC_2, F2SYNC,
- rxbuf, rdlen,
- pkt, NULL, NULL);
- bus->f2rxdata++;
-
- if (sdret < 0) {
- BRCMF_ERROR(("%s (nextlen): read %d"
- " bytes failed: %d\n",
- __func__, rdlen, sdret));
- brcmu_pkt_buf_free_skb(pkt);
- bus->drvr->rx_errors++;
- /* Force retry w/normal header read.
- * Don't attempt NAK for
- * gSPI
- */
- brcmf_sdbrcm_rxfail(bus, true,
- (bus->bus ==
- SPI_BUS) ? false :
- true);
- continue;
- }
- }
-
- /* Now check the header */
- memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN);
-
- /* Extract hardware header fields */
- len = get_unaligned_le16(bus->rxhdr);
- check = get_unaligned_le16(bus->rxhdr + sizeof(u16));
-
- /* All zeros means readahead info was bad */
- if (!(len | check)) {
- BRCMF_INFO(("%s (nextlen): read zeros in HW "
- "header???\n", __func__));
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
-
- /* Validate check bytes */
- if ((u16)~(len ^ check)) {
- BRCMF_ERROR(("%s (nextlen): HW hdr error:"
- " nextlen/len/check"
- " 0x%04x/0x%04x/0x%04x\n",
- __func__, nextlen, len, check));
- bus->rx_badhdr++;
- brcmf_sdbrcm_rxfail(bus, false, false);
- brcmf_sdbrcm_pktfree2(bus, pkt);
+ brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf);
+ if (pkt == NULL) {
+ /* Give up on data, request rtx of events */
+ brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n",
+ len, rdlen, rxseq);
continue;
}
- /* Validate frame length */
- if (len < SDPCM_HDRLEN) {
- BRCMF_ERROR(("%s (nextlen): HW hdr length "
- "invalid: %d\n", __func__, len));
- brcmf_sdbrcm_pktfree2(bus, pkt);
+ if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen,
+ &len) < 0)
continue;
- }
-
- /* Check for consistency withreadahead info */
- len_consistent = (nextlen != (roundup(len, 16) >> 4));
- if (len_consistent) {
- /* Mismatch, force retry w/normal
- header (may be >4K) */
- BRCMF_ERROR(("%s (nextlen): mismatch, "
- "nextlen %d len %d rnd %d; "
- "expected rxseq %d\n",
- __func__, nextlen,
- len, roundup(len, 16), rxseq));
- brcmf_sdbrcm_rxfail(bus, true,
- bus->bus != SPI_BUS);
- brcmf_sdbrcm_pktfree2(bus, pkt);
- continue;
- }
/* Extract software header fields */
chan = SDPCM_PACKET_CHANNEL(
@@ -4227,9 +1900,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
bus->rxhdr[SDPCM_FRAMETAG_LEN +
SDPCM_NEXTLEN_OFFSET];
if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
- BRCMF_INFO(("%s (nextlen): got frame w/nextlen"
- " too large (%d), seq %d\n",
- __func__, bus->nextlen, seq));
+ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
+ bus->nextlen, seq);
bus->nextlen = 0;
}
@@ -4252,17 +1924,16 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Check and update sequence number */
if (rxseq != seq) {
- BRCMF_INFO(("%s (nextlen): rx_seq %d, expected "
- "%d\n", __func__, seq, rxseq));
+ brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n",
+ seq, rxseq);
bus->rx_badseq++;
rxseq = seq;
}
/* Check window for sanity */
if ((u8) (txmax - bus->tx_seq) > 0x40) {
- BRCMF_ERROR(("%s: got unlikely tx max %d with "
- "tx_seq %d\n",
- __func__, txmax, bus->tx_seq));
+ brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
txmax = bus->tx_seq + 2;
}
bus->tx_max = txmax;
@@ -4280,34 +1951,19 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
#endif
if (chan == SDPCM_CONTROL_CHANNEL) {
- if (bus->bus == SPI_BUS) {
- brcmf_sdbrcm_read_control(bus, rxbuf,
- len, doff);
- } else {
- BRCMF_ERROR(("%s (nextlen): readahead"
- " on control packet %d?\n",
- __func__, seq));
- /* Force retry w/normal header read */
- bus->nextlen = 0;
- brcmf_sdbrcm_rxfail(bus, false, true);
- }
+ brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n",
+ seq);
+ /* Force retry w/normal header read */
+ bus->nextlen = 0;
+ brcmf_sdbrcm_rxfail(bus, false, true);
brcmf_sdbrcm_pktfree2(bus, pkt);
continue;
}
- if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
- BRCMF_ERROR(("Received %d bytes on %d channel."
- " Running out of " "rx pktbuf's or"
- " not yet malloced.\n",
- len, chan));
- continue;
- }
-
/* Validate data offset */
if ((doff < SDPCM_HDRLEN) || (doff > len)) {
- BRCMF_ERROR(("%s (nextlen): bad data offset %d:"
- " HW len %d min %d\n", __func__,
- doff, len, SDPCM_HDRLEN));
+ brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n",
+ doff, len, SDPCM_HDRLEN);
brcmf_sdbrcm_rxfail(bus, false, false);
brcmf_sdbrcm_pktfree2(bus, pkt);
continue;
@@ -4316,20 +1972,15 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* All done with this one -- now deliver the packet */
goto deliver;
}
- /* gSPI frames should not be handled in fractions */
- if (bus->bus == SPI_BUS)
- break;
/* Read frame header (hardware and software) */
- sdret = brcmf_sdcard_recv_buf(card,
- brcmf_sdcard_cur_sbwad(card),
- SDIO_FUNC_2, F2SYNC, bus->rxhdr, firstread,
- NULL, NULL, NULL);
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, bus->rxhdr,
+ BRCMF_FIRSTREAD, NULL);
bus->f2rxhdrs++;
if (sdret < 0) {
- BRCMF_ERROR(("%s: RXHEADER FAILED: %d\n", __func__,
- sdret));
+ brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret);
bus->rx_hdrfail++;
brcmf_sdbrcm_rxfail(bus, true, true);
continue;
@@ -4354,8 +2005,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Validate check bytes */
if ((u16) ~(len ^ check)) {
- BRCMF_ERROR(("%s: HW hdr err: len/check "
- "0x%04x/0x%04x\n", __func__, len, check));
+ brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n",
+ len, check);
bus->rx_badhdr++;
brcmf_sdbrcm_rxfail(bus, false, false);
continue;
@@ -4363,8 +2014,7 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Validate frame length */
if (len < SDPCM_HDRLEN) {
- BRCMF_ERROR(("%s: HW hdr length invalid: %d\n",
- __func__, len));
+ brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len);
continue;
}
@@ -4376,9 +2026,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Validate data offset */
if ((doff < SDPCM_HDRLEN) || (doff > len)) {
- BRCMF_ERROR(("%s: Bad data offset %d: HW len %d,"
- " min %d seq %d\n", __func__, doff,
- len, SDPCM_HDRLEN, seq));
+ brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n",
+ doff, len, SDPCM_HDRLEN, seq);
bus->rx_badhdr++;
brcmf_sdbrcm_rxfail(bus, false, false);
continue;
@@ -4388,9 +2037,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
bus->nextlen =
bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
- BRCMF_INFO(("%s (nextlen): got frame w/nextlen too"
- " large (%d), seq %d\n",
- __func__, bus->nextlen, seq));
+ brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n",
+ bus->nextlen, seq);
bus->nextlen = 0;
}
@@ -4410,16 +2058,15 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
/* Check and update sequence number */
if (rxseq != seq) {
- BRCMF_INFO(("%s: rx_seq %d, expected %d\n", __func__,
- seq, rxseq));
+ brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq);
bus->rx_badseq++;
rxseq = seq;
}
/* Check window for sanity */
if ((u8) (txmax - bus->tx_seq) > 0x40) {
- BRCMF_ERROR(("%s: unlikely tx max %d with tx_seq %d\n",
- __func__, txmax, bus->tx_seq));
+ brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n",
+ txmax, bus->tx_seq);
txmax = bus->tx_seq + 2;
}
bus->tx_max = txmax;
@@ -4435,61 +2082,59 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
SDPCM_GLOM_CHANNEL */
/* Length to read */
- rdlen = (len > firstread) ? (len - firstread) : 0;
+ rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0;
/* May pad read to blocksize for efficiency */
if (bus->roundup && bus->blocksize &&
(rdlen > bus->blocksize)) {
pad = bus->blocksize - (rdlen % bus->blocksize);
if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
- ((rdlen + pad + firstread) < MAX_RX_DATASZ))
+ ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ))
rdlen += pad;
} else if (rdlen % BRCMF_SDALIGN) {
rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN);
}
/* Satisfy length-alignment requirements */
- if (forcealign && (rdlen & (ALIGNMENT - 1)))
+ if (rdlen & (ALIGNMENT - 1))
rdlen = roundup(rdlen, ALIGNMENT);
- if ((rdlen + firstread) > MAX_RX_DATASZ) {
+ if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) {
/* Too long -- skip this frame */
- BRCMF_ERROR(("%s: too long: len %d rdlen %d\n",
- __func__, len, rdlen));
+ brcmf_dbg(ERROR, "too long: len %d rdlen %d\n",
+ len, rdlen);
bus->drvr->rx_errors++;
bus->rx_toolong++;
brcmf_sdbrcm_rxfail(bus, false, false);
continue;
}
- pkt = brcmu_pkt_buf_get_skb(rdlen + firstread + BRCMF_SDALIGN);
+ pkt = brcmu_pkt_buf_get_skb(rdlen +
+ BRCMF_FIRSTREAD + BRCMF_SDALIGN);
if (!pkt) {
/* Give up on data, request rtx of events */
- BRCMF_ERROR(("%s: brcmu_pkt_buf_get_skb failed:"
- " rdlen %d chan %d\n", __func__, rdlen,
- chan));
+ brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n",
+ rdlen, chan);
bus->drvr->rx_dropped++;
brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan));
continue;
}
/* Leave room for what we already read, and align remainder */
- skb_pull(pkt, firstread);
- PKTALIGN(pkt, rdlen, BRCMF_SDALIGN);
+ skb_pull(pkt, BRCMF_FIRSTREAD);
+ pkt_align(pkt, rdlen, BRCMF_SDALIGN);
/* Read the remaining frame data */
- sdret = brcmf_sdcard_recv_buf(card,
- brcmf_sdcard_cur_sbwad(card),
+ sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)),
- rdlen, pkt, NULL, NULL);
+ rdlen, pkt);
bus->f2rxdata++;
if (sdret < 0) {
- BRCMF_ERROR(("%s: read %d %s bytes failed: %d\n",
- __func__, rdlen,
- ((chan == SDPCM_EVENT_CHANNEL) ? "event"
- : ((chan == SDPCM_DATA_CHANNEL) ? "data"
- : "test")), sdret));
+ brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen,
+ ((chan == SDPCM_EVENT_CHANNEL) ? "event"
+ : ((chan == SDPCM_DATA_CHANNEL) ? "data"
+ : "test")), sdret);
brcmu_pkt_buf_free_skb(pkt);
bus->drvr->rx_errors++;
brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan));
@@ -4497,8 +2142,8 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
}
/* Copy the already-read portion */
- skb_push(pkt, firstread);
- memcpy(pkt->data, bus->rxhdr, firstread);
+ skb_push(pkt, BRCMF_FIRSTREAD);
+ memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD);
#ifdef BCMDBG
if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
@@ -4512,8 +2157,8 @@ deliver:
/* Save superframe descriptor and allocate packet frame */
if (chan == SDPCM_GLOM_CHANNEL) {
if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
- BRCMF_GLOM(("%s: glom descriptor, %d bytes:\n",
- __func__, len));
+ brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n",
+ len);
#ifdef BCMDBG
if (BRCMF_GLOM_ON()) {
printk(KERN_DEBUG "Glom Data:\n");
@@ -4526,8 +2171,8 @@ deliver:
skb_pull(pkt, SDPCM_HDRLEN);
bus->glomd = pkt;
} else {
- BRCMF_ERROR(("%s: glom superframe w/o "
- "descriptor!\n", __func__));
+ brcmf_dbg(ERROR, "%s: glom superframe w/o "
+ "descriptor!\n", __func__);
brcmf_sdbrcm_rxfail(bus, false, false);
}
continue;
@@ -4537,38 +2182,30 @@ deliver:
__skb_trim(pkt, len);
skb_pull(pkt, doff);
-#ifdef SDTEST
- /* Test channel packets are processed separately */
- if (chan == SDPCM_TEST_CHANNEL) {
- brcmf_sdbrcm_checkdied(bus, pkt, seq);
- continue;
- }
-#endif /* SDTEST */
-
if (pkt->len == 0) {
brcmu_pkt_buf_free_skb(pkt);
continue;
} else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) {
- BRCMF_ERROR(("%s: rx protocol error\n", __func__));
+ brcmf_dbg(ERROR, "rx protocol error\n");
brcmu_pkt_buf_free_skb(pkt);
bus->drvr->rx_errors++;
continue;
}
/* Unlock during rx call */
- brcmf_sdbrcm_sdunlock(bus);
+ up(&bus->sdsem);
brcmf_rx_frame(bus->drvr, ifidx, pkt, 1);
- brcmf_sdbrcm_sdlock(bus);
+ down(&bus->sdsem);
}
rxcount = maxframes - rxleft;
#ifdef BCMDBG
/* Message if we hit the limit */
- if (!rxleft && !sdtest)
- BRCMF_DATA(("%s: hit rx limit of %d frames\n", __func__,
- maxframes));
+ if (!rxleft)
+ brcmf_dbg(DATA, "hit rx limit of %d frames\n",
+ maxframes);
else
#endif /* BCMDBG */
- BRCMF_DATA(("%s: processed %d frames\n", __func__, rxcount));
+ brcmf_dbg(DATA, "processed %d frames\n", rxcount);
/* Back off rxseq if awaiting rtx, update rx_seq */
if (bus->rxskip)
rxseq--;
@@ -4577,100 +2214,243 @@ deliver:
return rxcount;
}
-static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus)
+static int
+brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags,
+ u8 *buf, uint nbytes, struct sk_buff *pkt)
{
- u32 intstatus = 0;
- u32 hmb_data;
- u8 fcbits;
- uint retries = 0;
+ return brcmf_sdcard_send_buf
+ (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt);
+}
- BRCMF_TRACE(("%s: Enter\n", __func__));
+static void
+brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
+{
+ up(&bus->sdsem);
+ wait_event_interruptible_timeout(bus->ctrl_wait,
+ (*lockvar == false), HZ * 2);
+ down(&bus->sdsem);
+ return;
+}
- /* Read mailbox data and ack that we did so */
- r_sdreg32(bus, &hmb_data,
- offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
+static void
+brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
+{
+ if (waitqueue_active(&bus->ctrl_wait))
+ wake_up_interruptible(&bus->ctrl_wait);
+ return;
+}
- if (retries <= retry_limit)
- w_sdreg32(bus, SMB_INT_ACK,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
- bus->f1regdata += 2;
+/* Writes a HW/SW header into the packet and sends it. */
+/* Assumes: (a) header space already there, (b) caller holds lock */
+static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt,
+ uint chan, bool free_pkt)
+{
+ int ret;
+ u8 *frame;
+ u16 len, pad = 0;
+ u32 swheader;
+ struct sk_buff *new;
+ int i;
- /* Dongle recomposed rx frames, accept them again */
- if (hmb_data & HMB_DATA_NAKHANDLED) {
- BRCMF_INFO(("Dongle reports NAK handled, expect rtx of %d\n",
- bus->rx_seq));
- if (!bus->rxskip)
- BRCMF_ERROR(("%s: unexpected NAKHANDLED!\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- bus->rxskip = false;
- intstatus |= I_HMB_FRAME_IND;
+ frame = (u8 *) (pkt->data);
+
+ /* Add alignment padding, allocate new packet if needed */
+ pad = ((unsigned long)frame % BRCMF_SDALIGN);
+ if (pad) {
+ if (skb_headroom(pkt) < pad) {
+ brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n",
+ skb_headroom(pkt), pad);
+ bus->drvr->tx_realloc++;
+ new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN);
+ if (!new) {
+ brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n",
+ pkt->len + BRCMF_SDALIGN);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pkt_align(new, pkt->len, BRCMF_SDALIGN);
+ memcpy(new->data, pkt->data, pkt->len);
+ if (free_pkt)
+ brcmu_pkt_buf_free_skb(pkt);
+ /* free the pkt if canned one is not used */
+ free_pkt = true;
+ pkt = new;
+ frame = (u8 *) (pkt->data);
+ /* precondition: (frame % BRCMF_SDALIGN) == 0) */
+ pad = 0;
+ } else {
+ skb_push(pkt, pad);
+ frame = (u8 *) (pkt->data);
+ /* precondition: pad + SDPCM_HDRLEN <= pkt->len */
+ memset(frame, 0, pad + SDPCM_HDRLEN);
+ }
}
+ /* precondition: pad < BRCMF_SDALIGN */
- /*
- * DEVREADY does not occur with gSPI.
- */
- if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
- bus->sdpcm_ver =
- (hmb_data & HMB_DATA_VERSION_MASK) >>
- HMB_DATA_VERSION_SHIFT;
- if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
- BRCMF_ERROR(("Version mismatch, dongle reports %d, "
- "expecting %d\n",
- bus->sdpcm_ver, SDPCM_PROT_VERSION));
- else
- BRCMF_INFO(("Dongle ready, protocol version %d\n",
- bus->sdpcm_ver));
+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+ len = (u16) (pkt->len);
+ *(__le16 *) frame = cpu_to_le16(len);
+ *(((__le16 *) frame) + 1) = cpu_to_le16(~len);
+
+ /* Software tag: channel, sequence number, data offset */
+ swheader =
+ ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
+ (((pad +
+ SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
+
+ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
+ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
+
+#ifdef BCMDBG
+ tx_packets[pkt->priority]++;
+ if (BRCMF_BYTES_ON() &&
+ (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
+ (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
+ printk(KERN_DEBUG "Tx Frame:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "TxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, min_t(u16, len, 16));
}
+#endif
- /*
- * Flow Control has been moved into the RX headers and this out of band
- * method isn't used any more.
- * remaining backward compatible with older dongles.
- */
- if (hmb_data & HMB_DATA_FC) {
- fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >>
- HMB_DATA_FCDATA_SHIFT;
+ /* Raise len to next SDIO block to eliminate tail command */
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ u16 pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize))
+ len += pad;
+ } else if (len % BRCMF_SDALIGN) {
+ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
+ }
- if (fcbits & ~bus->flowcontrol)
- bus->fc_xoff++;
+ /* Some controllers have trouble with odd bytes -- round to even */
+ if (len & (ALIGNMENT - 1))
+ len = roundup(len, ALIGNMENT);
- if (bus->flowcontrol & ~fcbits)
- bus->fc_xon++;
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, frame,
+ len, pkt);
+ bus->f2txdata++;
+
+ if (ret < 0) {
+ /* On failure, abort the command and terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;
+
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
+ NULL);
+ bus->f1regdata++;
+
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if ((hi == 0) && (lo == 0))
+ break;
+ }
- bus->fc_rcvd++;
- bus->flowcontrol = fcbits;
}
+ if (ret == 0)
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- /* Shouldn't be any others */
- if (hmb_data & ~(HMB_DATA_DEVREADY |
- HMB_DATA_NAKHANDLED |
- HMB_DATA_FC |
- HMB_DATA_FWREADY |
- HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) {
- BRCMF_ERROR(("Unknown mailbox data content: 0x%02x\n",
- hmb_data));
+done:
+ /* restore pkt buffer pointer before calling tx complete routine */
+ skb_pull(pkt, SDPCM_HDRLEN + pad);
+ up(&bus->sdsem);
+ brcmf_txcomplete(bus->drvr, pkt, ret != 0);
+ down(&bus->sdsem);
+
+ if (free_pkt)
+ brcmu_pkt_buf_free_skb(pkt);
+
+ return ret;
+}
+
+static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes)
+{
+ struct sk_buff *pkt;
+ u32 intstatus = 0;
+ uint retries = 0;
+ int ret = 0, prec_out;
+ uint cnt = 0;
+ uint datalen;
+ u8 tx_prec_map;
+
+ struct brcmf_pub *drvr = bus->drvr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ tx_prec_map = ~bus->flowcontrol;
+
+ /* Send frames until the limit or some other event */
+ for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) {
+ spin_lock_bh(&bus->txqlock);
+ pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out);
+ if (pkt == NULL) {
+ spin_unlock_bh(&bus->txqlock);
+ break;
+ }
+ spin_unlock_bh(&bus->txqlock);
+ datalen = pkt->len - SDPCM_HDRLEN;
+
+ ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true);
+ if (ret)
+ bus->drvr->tx_errors++;
+ else
+ bus->drvr->dstats.tx_bytes += datalen;
+
+ /* In poll mode, need to check for other events */
+ if (!bus->intr && cnt) {
+ /* Check device status, signal pending interrupt */
+ r_sdreg32(bus, &intstatus,
+ offsetof(struct sdpcmd_regs, intstatus),
+ &retries);
+ bus->f2txdata++;
+ if (brcmf_sdcard_regfail(bus->sdiodev))
+ break;
+ if (intstatus & bus->hostintmask)
+ bus->ipend = true;
+ }
}
- return intstatus;
+ /* Deflow-control stack if needed */
+ if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) &&
+ drvr->txoff && (pktq_len(&bus->txq) < TXLOW))
+ brcmf_txflowcontrol(drvr, 0, OFF);
+
+ return cnt;
}
static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
{
- struct brcmf_sdio_card *card = bus->card;
u32 intstatus, newstatus = 0;
uint retries = 0;
- uint rxlimit = brcmf_rxbound; /* Rx frames to read before resched */
- uint txlimit = brcmf_txbound; /* Tx frames to send before resched */
+ uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
+ uint txlimit = bus->txbound; /* Tx frames to send before resched */
uint framecnt = 0; /* Temporary counter of tx/rx frames */
bool rxdone = true; /* Flag for no more read data */
bool resched = false; /* Flag indicating resched wanted */
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
/* Start with leftover status bits */
intstatus = bus->intstatus;
- brcmf_sdbrcm_sdlock(bus);
+ down(&bus->sdsem);
/* If waiting for HTAVAIL, check status */
if (bus->clkstate == CLK_PENDING) {
@@ -4679,41 +2459,41 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
#ifdef BCMDBG
/* Check for inconsistent device control */
- devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
if (err) {
- BRCMF_ERROR(("%s: error reading DEVCTL: %d\n",
- __func__, err));
+ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
bus->drvr->busstate = BRCMF_BUS_DOWN;
}
#endif /* BCMDBG */
/* Read CSR, if clock on switch to AVAIL, else ignore */
- clkctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
- BRCMF_ERROR(("%s: error reading CSR: %d\n", __func__,
- err));
+ brcmf_dbg(ERROR, "error reading CSR: %d\n",
+ err);
bus->drvr->busstate = BRCMF_BUS_DOWN;
}
- BRCMF_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
- devctl, clkctl));
+ brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n",
+ devctl, clkctl);
if (SBSDIO_HTAV(clkctl)) {
- devctl = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
if (err) {
- BRCMF_ERROR(("%s: error reading DEVCTL: %d\n",
- __func__, err));
+ brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
+ err);
bus->drvr->busstate = BRCMF_BUS_DOWN;
}
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
if (err) {
- BRCMF_ERROR(("%s: error writing DEVCTL: %d\n",
- __func__, err));
+ brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
+ err);
bus->drvr->busstate = BRCMF_BUS_DOWN;
}
bus->clkstate = CLK_AVAIL;
@@ -4722,7 +2502,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
}
}
- BUS_WAKE(bus);
+ bus_wake(bus);
/* Make sure backplane clock is on */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true);
@@ -4735,7 +2515,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus), &retries);
bus->f1regdata++;
- if (brcmf_sdcard_regfail(bus->card))
+ if (brcmf_sdcard_regfail(bus->sdiodev))
newstatus = 0;
newstatus &= bus->hostintmask;
bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
@@ -4776,23 +2556,23 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
/* Generally don't ask for these, can get CRC errors... */
if (intstatus & I_WR_OOSYNC) {
- BRCMF_ERROR(("Dongle reports WR_OOSYNC\n"));
+ brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
intstatus &= ~I_WR_OOSYNC;
}
if (intstatus & I_RD_OOSYNC) {
- BRCMF_ERROR(("Dongle reports RD_OOSYNC\n"));
+ brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n");
intstatus &= ~I_RD_OOSYNC;
}
if (intstatus & I_SBINT) {
- BRCMF_ERROR(("Dongle reports SBINT\n"));
+ brcmf_dbg(ERROR, "Dongle reports SBINT\n");
intstatus &= ~I_SBINT;
}
/* Would be active due to wake-wlan in gSPI */
if (intstatus & I_CHIPACTIVE) {
- BRCMF_INFO(("Dongle reports CHIPACTIVE\n"));
+ brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n");
intstatus &= ~I_CHIPACTIVE;
}
@@ -4812,45 +2592,36 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus)
bus->intstatus = intstatus;
clkwait:
- /* Re-enable interrupts to detect new device events (mailbox, rx frame)
- * or clock availability. (Allows tx loop to check ipend if desired.)
- * (Unless register access seems hosed, as we may not be able to ACK...)
- */
- if (bus->intr && bus->intdis && !brcmf_sdcard_regfail(card)) {
- BRCMF_INTR(("%s: enable SDIO interrupts, rxdone %d"
- " framecnt %d\n", __func__, rxdone, framecnt));
- bus->intdis = false;
- brcmf_sdcard_intr_enable(card);
- }
-
- if (DATAOK(bus) && bus->ctrl_frame_stat &&
+ if (data_ok(bus) && bus->ctrl_frame_stat &&
(bus->clkstate == CLK_AVAIL)) {
int ret, i;
- ret = brcmf_sdbrcm_send_buf(bus, brcmf_sdcard_cur_sbwad(card),
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf,
- (u32) bus->ctrl_frame_len, NULL, NULL, NULL);
+ (u32) bus->ctrl_frame_len, NULL);
if (ret < 0) {
/* On failure, abort the command and
terminate the frame */
- BRCMF_INFO(("%s: sdio error %d, abort command and "
- "terminate frame.\n", __func__, ret));
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
bus->tx_sderrs++;
- brcmf_sdcard_abort(card, SDIO_FUNC_2);
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1,
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
NULL);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCHI,
NULL);
- lo = brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCLO,
NULL);
bus->f1regdata += 2;
@@ -4862,15 +2633,15 @@ clkwait:
if (ret == 0)
bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- BRCMF_INFO(("Return_dpc value is : %d\n", ret));
+ brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret);
bus->ctrl_frame_stat = false;
brcmf_sdbrcm_wait_event_wakeup(bus);
}
/* Send queued frames (limit 1 if rx may still be pending) */
else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit
- && DATAOK(bus)) {
- framecnt = rxdone ? txlimit : min(txlimit, brcmf_txminmax);
+ && data_ok(bus)) {
+ framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax);
framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt);
txlimit -= framecnt;
}
@@ -4880,19 +2651,17 @@ clkwait:
/* On failed register access, all bets are off:
no resched or interrupts */
if ((bus->drvr->busstate == BRCMF_BUS_DOWN) ||
- brcmf_sdcard_regfail(card)) {
- BRCMF_ERROR(("%s: failed backplane access over SDIO, halting "
- "operation %d\n", __func__,
- brcmf_sdcard_regfail(card)));
+ brcmf_sdcard_regfail(bus->sdiodev)) {
+ brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
+ brcmf_sdcard_regfail(bus->sdiodev));
bus->drvr->busstate = BRCMF_BUS_DOWN;
bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) {
- BRCMF_INFO(("%s: rescheduled due to CLK_PENDING awaiting "
- "I_CHIPACTIVE interrupt\n", __func__));
+ brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n");
resched = true;
} else if (bus->intstatus || bus->ipend ||
(!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol)
- && DATAOK(bus)) || PKT_AVAILABLE()) {
+ && data_ok(bus)) || PKT_AVAILABLE()) {
resched = true;
}
@@ -4905,1010 +2674,733 @@ clkwait:
brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
}
- brcmf_sdbrcm_sdunlock(bus);
+ up(&bus->sdsem);
return resched;
}
-void brcmf_sdbrcm_isr(void *arg)
+static int brcmf_sdbrcm_dpc_thread(void *data)
{
- struct brcmf_bus *bus = (struct brcmf_bus *) arg;
- struct brcmf_sdio_card *card;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (!bus) {
- BRCMF_ERROR(("%s : bus is null pointer , exit\n", __func__));
- return;
- }
- card = bus->card;
-
- if (bus->drvr->busstate == BRCMF_BUS_DOWN) {
- BRCMF_ERROR(("%s : bus is down. we have nothing to do\n",
- __func__));
- return;
- }
- /* Count the interrupt call */
- bus->intrcount++;
- bus->ipend = true;
+ struct brcmf_bus *bus = (struct brcmf_bus *) data;
- /* Shouldn't get this interrupt if we're sleeping? */
- if (bus->sleeping) {
- BRCMF_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
- return;
+ allow_signal(SIGTERM);
+ /* Run until signal received */
+ while (1) {
+ if (kthread_should_stop())
+ break;
+ if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
+ /* Call bus dpc unless it indicated down
+ (then clean stop) */
+ if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
+ if (brcmf_sdbrcm_dpc(bus))
+ complete(&bus->dpc_wait);
+ } else {
+ /* after stopping the bus, exit thread */
+ brcmf_sdbrcm_bus_stop(bus);
+ bus->dpc_tsk = NULL;
+ break;
+ }
+ } else
+ break;
}
-
- /* Disable additional interrupts (is this needed now)? */
- if (bus->intr)
- BRCMF_INTR(("%s: disable SDIO interrupts\n", __func__));
- else
- BRCMF_ERROR(("brcmf_sdbrcm_isr() w/o interrupt configured!\n"));
-
- brcmf_sdcard_intr_disable(card);
- bus->intdis = true;
-
-#if defined(SDIO_ISR_THREAD)
- BRCMF_TRACE(("Calling brcmf_sdbrcm_dpc() from %s\n", __func__));
- while (brcmf_sdbrcm_dpc(bus))
- ;
-#else
- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
-#endif
-
+ return 0;
}
-#ifdef SDTEST
-static void brcmf_sdbrcm_pktgen_init(struct brcmf_bus *bus)
+int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt)
{
- /* Default to specified length, or full range */
- if (brcmf_pktgen_len) {
- bus->pktgen_maxlen = min(brcmf_pktgen_len,
- BRCMF_MAX_PKTGEN_LEN);
- bus->pktgen_minlen = bus->pktgen_maxlen;
- } else {
- bus->pktgen_maxlen = BRCMF_MAX_PKTGEN_LEN;
- bus->pktgen_minlen = 0;
- }
- bus->pktgen_len = (u16) bus->pktgen_minlen;
+ int ret = -EBADE;
+ uint datalen, prec;
- /* Default to per-watchdog burst with 10s print time */
- bus->pktgen_freq = 1;
- bus->pktgen_print = 10000 / brcmf_watchdog_ms;
- bus->pktgen_count = (brcmf_pktgen * brcmf_watchdog_ms + 999) / 1000;
+ brcmf_dbg(TRACE, "Enter\n");
- /* Default to echo mode */
- bus->pktgen_mode = BRCMF_PKTGEN_ECHO;
- bus->pktgen_stop = 1;
-}
+ datalen = pkt->len;
-static void brcmf_sdbrcm_pktgen(struct brcmf_bus *bus)
-{
- struct sk_buff *pkt;
- u8 *data;
- uint pktcount;
- uint fillbyte;
- u16 len;
+ /* Add space for the header */
+ skb_push(pkt, SDPCM_HDRLEN);
+ /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */
- /* Display current count if appropriate */
- if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
- bus->pktgen_ptick = 0;
- printk(KERN_DEBUG "%s: send attempts %d rcvd %d\n",
- __func__, bus->pktgen_sent, bus->pktgen_rcvd);
- }
+ prec = prio2prec((pkt->priority & PRIOMASK));
- /* For recv mode, just make sure dongle has started sending */
- if (bus->pktgen_mode == BRCMF_PKTGEN_RECV) {
- if (!bus->pktgen_rcvd)
- brcmf_sdbrcm_sdtest_set(bus, true);
- return;
+ /* Check for existing queue, current flow-control,
+ pending event, or pending clock */
+ brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq));
+ bus->fcqueued++;
+
+ /* Priority based enq */
+ spin_lock_bh(&bus->txqlock);
+ if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) {
+ skb_pull(pkt, SDPCM_HDRLEN);
+ brcmf_txcomplete(bus->drvr, pkt, false);
+ brcmu_pkt_buf_free_skb(pkt);
+ brcmf_dbg(ERROR, "out of bus->txq !!!\n");
+ ret = -ENOSR;
+ } else {
+ ret = 0;
}
+ spin_unlock_bh(&bus->txqlock);
- /* Otherwise, generate or request the specified number of packets */
- for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
- /* Stop if total has been reached */
- if (bus->pktgen_total
- && (bus->pktgen_sent >= bus->pktgen_total)) {
- bus->pktgen_count = 0;
- break;
- }
-
- /* Allocate an appropriate-sized packet */
- len = bus->pktgen_len;
- pkt = brcmu_pkt_buf_get_skb(
- len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + BRCMF_SDALIGN,
- true);
- if (!pkt) {
- BRCMF_ERROR(("%s: brcmu_pkt_buf_get_skb failed!\n",
- __func__));
- break;
- }
- PKTALIGN(pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN),
- BRCMF_SDALIGN);
- data = (u8 *) (pkt->data) + SDPCM_HDRLEN;
-
- /* Write test header cmd and extra based on mode */
- switch (bus->pktgen_mode) {
- case BRCMF_PKTGEN_ECHO:
- *data++ = SDPCM_TEST_ECHOREQ;
- *data++ = (u8) bus->pktgen_sent;
- break;
-
- case BRCMF_PKTGEN_SEND:
- *data++ = SDPCM_TEST_DISCARD;
- *data++ = (u8) bus->pktgen_sent;
- break;
-
- case BRCMF_PKTGEN_RXBURST:
- *data++ = SDPCM_TEST_BURST;
- *data++ = (u8) bus->pktgen_count;
- break;
-
- default:
- BRCMF_ERROR(("Unrecognized pktgen mode %d\n",
- bus->pktgen_mode));
- brcmu_pkt_buf_free_skb(pkt, true);
- bus->pktgen_count = 0;
- return;
- }
-
- /* Write test header length field */
- *data++ = (len >> 0);
- *data++ = (len >> 8);
-
- /* Then fill in the remainder -- N/A for burst,
- but who cares... */
- for (fillbyte = 0; fillbyte < len; fillbyte++)
- *data++ =
- SDPCM_TEST_FILL(fillbyte, (u8) bus->pktgen_sent);
+ if (pktq_len(&bus->txq) >= TXHI)
+ brcmf_txflowcontrol(bus->drvr, 0, ON);
#ifdef BCMDBG
- if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) {
- data = (u8 *) (pkt->data) + SDPCM_HDRLEN;
- printk(KERN_DEBUG "brcmf_sdbrcm_pktgen: Tx Data:\n");
- print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, data,
- pkt->len - SDPCM_HDRLEN);
- }
+ if (pktq_plen(&bus->txq, prec) > qcount[prec])
+ qcount[prec] = pktq_plen(&bus->txq, prec);
#endif
-
- /* Send it */
- if (brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true)) {
- bus->pktgen_fail++;
- if (bus->pktgen_stop
- && bus->pktgen_stop == bus->pktgen_fail)
- bus->pktgen_count = 0;
- }
- bus->pktgen_sent++;
-
- /* Bump length if not fixed, wrap at max */
- if (++bus->pktgen_len > bus->pktgen_maxlen)
- bus->pktgen_len = (u16) bus->pktgen_minlen;
-
- /* Special case for burst mode: just send one request! */
- if (bus->pktgen_mode == BRCMF_PKTGEN_RXBURST)
- break;
+ /* Schedule DPC if needed to send queued packet(s) */
+ if (!bus->dpc_sched) {
+ bus->dpc_sched = true;
+ if (bus->dpc_tsk)
+ complete(&bus->dpc_wait);
}
-}
-
-static void brcmf_sdbrcm_sdtest_set(struct brcmf_bus *bus, bool start)
-{
- struct sk_buff *pkt;
- u8 *data;
- /* Allocate the packet */
- pkt = brcmu_pkt_buf_get_skb(SDPCM_HDRLEN + SDPCM_TEST_HDRLEN +
- BRCMF_SDALIGN, true);
- if (!pkt) {
- BRCMF_ERROR(("%s: brcmu_pkt_buf_get_skb failed!\n", __func__));
- return;
- }
- PKTALIGN(pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), BRCMF_SDALIGN);
- data = (u8 *) (pkt->data) + SDPCM_HDRLEN;
-
- /* Fill in the test header */
- *data++ = SDPCM_TEST_SEND;
- *data++ = start;
- *data++ = (bus->pktgen_maxlen >> 0);
- *data++ = (bus->pktgen_maxlen >> 8);
-
- /* Send it */
- if (brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true))
- bus->pktgen_fail++;
+ return ret;
}
-static void
-brcmf_sdbrcm_checkdied(struct brcmf_bus *bus, struct sk_buff *pkt, uint seq)
+static int
+brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data,
+ uint size)
{
- u8 *data;
- uint pktlen;
+ int bcmerror = 0;
+ u32 sdaddr;
+ uint dsize;
- u8 cmd;
- u8 extra;
- u16 len;
- u16 offset;
-
- /* Check for min length */
- pktlen = pkt->len;
- if (pktlen < SDPCM_TEST_HDRLEN) {
- BRCMF_ERROR(("brcmf_sdbrcm_checkdied: toss runt frame, pktlen "
- "%d\n", pktlen));
- brcmu_pkt_buf_free_skb(pkt, false);
- return;
- }
+ /* Determine initial transfer parameters */
+ sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
+ if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
+ dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
+ else
+ dsize = size;
- /* Extract header fields */
- data = pkt->data;
- cmd = *data++;
- extra = *data++;
- len = *data++;
- len += *data++ << 8;
-
- /* Check length for relevant commands */
- if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ
- || cmd == SDPCM_TEST_ECHORSP) {
- if (pktlen != len + SDPCM_TEST_HDRLEN) {
- BRCMF_ERROR(("brcmf_sdbrcm_checkdied: frame length "
- "mismatch, pktlen %d seq %d"
- " cmd %d extra %d len %d\n",
- pktlen, seq, cmd, extra, len));
- brcmu_pkt_buf_free_skb(pkt, false);
- return;
- }
+ /* Set the backplane window to include the start address */
+ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "window change failed\n");
+ goto xfer_done;
}
- /* Process as per command */
- switch (cmd) {
- case SDPCM_TEST_ECHOREQ:
- /* Rx->Tx turnaround ok (even on NDIS w/current
- implementation) */
- *(u8 *) (pkt->data) = SDPCM_TEST_ECHORSP;
- if (brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, true) == 0)
- bus->pktgen_sent++;
- else {
- bus->pktgen_fail++;
- brcmu_pkt_buf_free_skb(pkt, false);
- }
- bus->pktgen_rcvd++;
- break;
-
- case SDPCM_TEST_ECHORSP:
- if (bus->ext_loop) {
- brcmu_pkt_buf_free_skb(pkt, false);
- bus->pktgen_rcvd++;
+ /* Do the transfer(s) */
+ while (size) {
+ brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n",
+ write ? "write" : "read", dsize,
+ sdaddr, address & SBSDIO_SBWINDOW_MASK);
+ bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write,
+ sdaddr, data, dsize);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "membytes transfer failed\n");
break;
}
- for (offset = 0; offset < len; offset++, data++) {
- if (*data != SDPCM_TEST_FILL(offset, extra)) {
- BRCMF_ERROR(("brcmf_sdbrcm_checkdied: echo"
- " data mismatch: "
- "offset %d (len %d) "
- "expect 0x%02x rcvd 0x%02x\n",
- offset, len,
- SDPCM_TEST_FILL(offset, extra),
- *data));
+ /* Adjust for next transfer (if any) */
+ size -= dsize;
+ if (size) {
+ data += dsize;
+ address += dsize;
+ bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev,
+ address);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "window change failed\n");
break;
}
- }
- brcmu_pkt_buf_free_skb(pkt, false);
- bus->pktgen_rcvd++;
- break;
-
- case SDPCM_TEST_DISCARD:
- brcmu_pkt_buf_free_skb(pkt, false);
- bus->pktgen_rcvd++;
- break;
-
- case SDPCM_TEST_BURST:
- case SDPCM_TEST_SEND:
- default:
- BRCMF_INFO(("brcmf_sdbrcm_checkdied: unsupported or unknown "
- "command, pktlen %d seq %d" " cmd %d extra %d"
- " len %d\n", pktlen, seq, cmd, extra, len));
- brcmu_pkt_buf_free_skb(pkt, false);
- break;
- }
-
- /* For recv mode, stop at limie (and tell dongle to stop sending) */
- if (bus->pktgen_mode == BRCMF_PKTGEN_RECV) {
- if (bus->pktgen_total
- && (bus->pktgen_rcvd >= bus->pktgen_total)) {
- bus->pktgen_count = 0;
- brcmf_sdbrcm_sdtest_set(bus, false);
- }
- }
-}
-#endif /* SDTEST */
-
-extern bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
-{
- struct brcmf_bus *bus;
-
- BRCMF_TIMER(("%s: Enter\n", __func__));
-
- bus = drvr->bus;
-
- if (bus->drvr->dongle_reset)
- return false;
-
- /* Ignore the timer if simulating bus down */
- if (bus->sleeping)
- return false;
-
- brcmf_sdbrcm_sdlock(bus);
-
- /* Poll period: check device if appropriate. */
- if (bus->poll && (++bus->polltick >= bus->pollrate)) {
- u32 intstatus = 0;
-
- /* Reset poll tick */
- bus->polltick = 0;
-
- /* Check device if no interrupts */
- if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
-
- if (!bus->dpc_sched) {
- u8 devpend;
- devpend = brcmf_sdcard_cfg_read(bus->card,
- SDIO_FUNC_0, SDIO_CCCR_INTx,
- NULL);
- intstatus =
- devpend & (INTR_STATUS_FUNC1 |
- INTR_STATUS_FUNC2);
- }
-
- /* If there is something, make like the ISR and
- schedule the DPC */
- if (intstatus) {
- bus->pollcnt++;
- bus->ipend = true;
- if (bus->intr)
- brcmf_sdcard_intr_disable(bus->card);
-
- bus->dpc_sched = true;
- brcmf_sdbrcm_sched_dpc(bus);
-
- }
- }
-
- /* Update interrupt tracking */
- bus->lastintrs = bus->intrcount;
- }
-#ifdef BCMDBG
- /* Poll for console output periodically */
- if (drvr->busstate == BRCMF_BUS_DATA && brcmf_console_ms != 0) {
- bus->console.count += brcmf_watchdog_ms;
- if (bus->console.count >= brcmf_console_ms) {
- bus->console.count -= brcmf_console_ms;
- /* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- if (brcmf_sdbrcm_readconsole(bus) < 0)
- brcmf_console_ms = 0; /* On error,
- stop trying */
- }
- }
-#endif /* BCMDBG */
-
-#ifdef SDTEST
- /* Generate packets if configured */
- if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
- /* Make sure backplane clock is on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- bus->pktgen_tick = 0;
- brcmf_sdbrcm_pktgen(bus);
- }
-#endif
-
- /* On idle timeout clear activity flag and/or turn off clock */
- if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
- if (++bus->idlecount >= bus->idletime) {
- bus->idlecount = 0;
- if (bus->activity) {
- bus->activity = false;
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
- } else {
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
- }
+ sdaddr = 0;
+ dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size);
}
}
- brcmf_sdbrcm_sdunlock(bus);
+xfer_done:
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad))
+ brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n",
+ bus->sdiodev->sbwad);
- return bus->ipend;
+ return bcmerror;
}
#ifdef BCMDBG
-static int brcmf_sdbrcm_bus_console_in(struct brcmf_pub *drvr,
- unsigned char *msg, uint msglen)
+#define CONSOLE_LINE_MAX 192
+
+static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus)
{
- struct brcmf_bus *bus = drvr->bus;
- u32 addr, val;
+ struct brcmf_console *c = &bus->console;
+ u8 line[CONSOLE_LINE_MAX], ch;
+ u32 n, idx, addr;
int rv;
- struct sk_buff *pkt;
- /* Address could be zero if CONSOLE := 0 in dongle Makefile */
+ /* Don't do anything until FWREADY updates console address */
if (bus->console_addr == 0)
- return -ENOTSUPP;
+ return 0;
- /* Exclusive bus access */
- brcmf_sdbrcm_sdlock(bus);
+ /* Read console log struct */
+ addr = bus->console_addr + offsetof(struct rte_console, log_le);
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le,
+ sizeof(c->log_le));
+ if (rv < 0)
+ return rv;
- /* Don't allow input if dongle is in reset */
- if (bus->drvr->dongle_reset) {
- brcmf_sdbrcm_sdunlock(bus);
- return -EPERM;
+ /* Allocate console buffer (one time only) */
+ if (c->buf == NULL) {
+ c->bufsize = le32_to_cpu(c->log_le.buf_size);
+ c->buf = kmalloc(c->bufsize, GFP_ATOMIC);
+ if (c->buf == NULL)
+ return -ENOMEM;
}
- /* Request clock to allow SDIO accesses */
- BUS_WAKE(bus);
- /* No pend allowed since txpkt is called later, ht clk has to be on */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ idx = le32_to_cpu(c->log_le.idx);
- /* Zero cbuf_index */
- addr = bus->console_addr + offsetof(struct rte_console, cbuf_idx);
- val = cpu_to_le32(0);
- rv = brcmf_sdbrcm_membytes(bus, true, addr, (u8 *)&val, sizeof(val));
- if (rv < 0)
- goto done;
+ /* Protect against corrupt value */
+ if (idx > c->bufsize)
+ return -EBADE;
- /* Write message into cbuf */
- addr = bus->console_addr + offsetof(struct rte_console, cbuf);
- rv = brcmf_sdbrcm_membytes(bus, true, addr, (u8 *)msg, msglen);
- if (rv < 0)
- goto done;
+ /* Skip reading the console buffer if the index pointer
+ has not moved */
+ if (idx == c->last)
+ return 0;
- /* Write length into vcons_in */
- addr = bus->console_addr + offsetof(struct rte_console, vcons_in);
- val = cpu_to_le32(msglen);
- rv = brcmf_sdbrcm_membytes(bus, true, addr, (u8 *)&val, sizeof(val));
+ /* Read the console buffer */
+ addr = le32_to_cpu(c->log_le.buf);
+ rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize);
if (rv < 0)
- goto done;
+ return rv;
- /* Bump dongle by sending an empty event pkt.
- * sdpcm_sendup (RX) checks for virtual console input.
- */
- pkt = brcmu_pkt_buf_get_skb(4 + SDPCM_RESERVE);
- if ((pkt != NULL) && bus->clkstate == CLK_AVAIL)
- brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, true);
+ while (c->last != idx) {
+ for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
+ if (c->last == idx) {
+ /* This would output a partial line.
+ * Instead, back up
+ * the buffer pointer and output this
+ * line next time around.
+ */
+ if (c->last >= n)
+ c->last -= n;
+ else
+ c->last = c->bufsize - n;
+ goto break2;
+ }
+ ch = c->buf[c->last];
+ c->last = (c->last + 1) % c->bufsize;
+ if (ch == '\n')
+ break;
+ line[n] = ch;
+ }
-done:
- if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
- bus->activity = false;
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
+ if (n > 0) {
+ if (line[n - 1] == '\r')
+ n--;
+ line[n] = 0;
+ printk(KERN_DEBUG "CONSOLE: %s\n", line);
+ }
}
+break2:
- brcmf_sdbrcm_sdunlock(bus);
-
- return rv;
+ return 0;
}
#endif /* BCMDBG */
-static bool brcmf_sdbrcm_chipmatch(u16 chipid)
-{
- if (chipid == BCM4325_CHIP_ID)
- return true;
- if (chipid == BCM4329_CHIP_ID)
- return true;
- if (chipid == BCM4319_CHIP_ID)
- return true;
- return false;
-}
-
-static void *brcmf_sdbrcm_probe(u16 venid, u16 devid, u16 bus_no,
- u16 slot, u16 func, uint bustype, u32 regsva,
- void *card)
+static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len)
{
+ int i;
int ret;
- struct brcmf_bus *bus;
-
- /* Init global variables at run-time, not as part of the declaration.
- * This is required to support init/de-init of the driver.
- * Initialization
- * of globals as part of the declaration results in non-deterministic
- * behavior since the value of the globals may be different on the
- * first time that the driver is initialized vs subsequent
- * initializations.
- */
- brcmf_txbound = BRCMF_TXBOUND;
- brcmf_rxbound = BRCMF_RXBOUND;
- brcmf_alignctl = true;
- sd1idle = true;
- brcmf_readahead = true;
- retrydata = false;
- brcmf_dongle_memsize = 0;
- brcmf_txminmax = BRCMF_TXMINMAX;
- forcealign = true;
+ bus->ctrl_frame_stat = false;
+ ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad,
+ SDIO_FUNC_2, F2SYNC, frame, len, NULL);
- brcmf_c_init();
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
- BRCMF_INFO(("%s: venid 0x%04x devid 0x%04x\n", __func__, venid, devid));
+ if (ret < 0) {
+ /* On failure, abort the command and terminate the frame */
+ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n",
+ ret);
+ bus->tx_sderrs++;
- /* We make an assumption about address window mappings:
- * regsva == SI_ENUM_BASE*/
+ brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- /* SDIO car passes venid and devid based on CIS parsing -- but
- * low-power start
- * means early parse could fail, so here we should get either an ID
- * we recognize OR (-1) indicating we must request power first.
- */
- /* Check the Vendor ID */
- switch (venid) {
- case 0x0000:
- case PCI_VENDOR_ID_BROADCOM:
- break;
- default:
- BRCMF_ERROR(("%s: unknown vendor: 0x%04x\n", __func__, venid));
- return NULL;
- }
-
- /* Check the Device ID and make sure it's one that we support */
- switch (devid) {
- case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
- case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
- case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
- BRCMF_INFO(("%s: found 4325 Dongle\n", __func__));
- break;
- case BCM4329_D11NDUAL_ID: /* 4329 802.11n dualband device */
- case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
- case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
- case 0x4329:
- BRCMF_INFO(("%s: found 4329 Dongle\n", __func__));
- break;
- case BCM4319_D11N_ID: /* 4319 802.11n id */
- case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
- case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
- BRCMF_INFO(("%s: found 4319 Dongle\n", __func__));
- break;
- case 0:
- BRCMF_INFO(("%s: allow device id 0, will check chip"
- " internals\n", __func__));
- break;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
+ bus->f1regdata++;
- default:
- BRCMF_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
- __func__, venid, devid));
- return NULL;
+ for (i = 0; i < 3; i++) {
+ u8 hi, lo;
+ hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ NULL);
+ lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ NULL);
+ bus->f1regdata += 2;
+ if (hi == 0 && lo == 0)
+ break;
+ }
+ return ret;
}
- /* Allocate private bus interface state */
- bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
- if (!bus) {
- BRCMF_ERROR(("%s: kmalloc of struct dhd_bus failed\n",
- __func__));
- goto fail;
- }
- bus->card = card;
- bus->cl_devid = (u16) devid;
- bus->bus = BRCMF_BUS;
- bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
- bus->usebufpool = false; /* Use bufpool if allocated,
- else use locally malloced rxbuf */
+ bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
- /* attempt to attach to the dongle */
- if (!(brcmf_sdbrcm_probe_attach(bus, card, regsva, devid))) {
- BRCMF_ERROR(("%s: brcmf_sdbrcm_probe_attach failed\n",
- __func__));
- goto fail;
- }
-
- spin_lock_init(&bus->txqlock);
- init_waitqueue_head(&bus->ctrl_wait);
+ return ret;
+}
- /* Set up the watchdog timer */
- init_timer(&bus->timer);
- bus->timer.data = (unsigned long)bus;
- bus->timer.function = brcmf_sdbrcm_watchdog;
+int
+brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+{
+ u8 *frame;
+ u16 len;
+ u32 swheader;
+ uint retries = 0;
+ u8 doff = 0;
+ int ret = -1;
- /* Initialize thread based operation and lock */
- if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)) {
- bus->threads_only = true;
- sema_init(&bus->sdsem, 1);
- } else {
- bus->threads_only = false;
- spin_lock_init(&bus->sdlock);
- }
+ brcmf_dbg(TRACE, "Enter\n");
- if (brcmf_dpc_prio >= 0) {
- /* Initialize watchdog thread */
- init_completion(&bus->watchdog_wait);
- bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
- bus, "brcmf_watchdog");
- if (IS_ERR(bus->watchdog_tsk)) {
- printk(KERN_WARNING
- "brcmf_watchdog thread failed to start\n");
- bus->watchdog_tsk = NULL;
- }
- } else
- bus->watchdog_tsk = NULL;
+ /* Back the pointer to make a room for bus header */
+ frame = msg - SDPCM_HDRLEN;
+ len = (msglen += SDPCM_HDRLEN);
- /* Set up the bottom half handler */
- if (brcmf_dpc_prio >= 0) {
- /* Initialize DPC thread */
- init_completion(&bus->dpc_wait);
- bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
- bus, "brcmf_dpc");
- if (IS_ERR(bus->dpc_tsk)) {
- printk(KERN_WARNING
- "brcmf_dpc thread failed to start\n");
- bus->dpc_tsk = NULL;
- }
- } else {
- tasklet_init(&bus->tasklet, brcmf_sdbrcm_dpc_tasklet,
- (unsigned long)bus);
- bus->dpc_tsk = NULL;
- }
+ /* Add alignment padding (optional for ctl frames) */
+ doff = ((unsigned long)frame % BRCMF_SDALIGN);
+ if (doff) {
+ frame -= doff;
+ len += doff;
+ msglen += doff;
+ memset(frame, 0, doff + SDPCM_HDRLEN);
+ }
+ /* precondition: doff < BRCMF_SDALIGN */
+ doff += SDPCM_HDRLEN;
- /* Attach to the brcmf/OS/network interface */
- bus->drvr = brcmf_attach(bus, SDPCM_RESERVE);
- if (!bus->drvr) {
- BRCMF_ERROR(("%s: brcmf_attach failed\n", __func__));
- goto fail;
+ /* Round send length to next SDIO block */
+ if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
+ u16 pad = bus->blocksize - (len % bus->blocksize);
+ if ((pad <= bus->roundup) && (pad < bus->blocksize))
+ len += pad;
+ } else if (len % BRCMF_SDALIGN) {
+ len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN);
}
- /* Allocate buffers */
- if (!(brcmf_sdbrcm_probe_malloc(bus, card))) {
- BRCMF_ERROR(("%s: brcmf_sdbrcm_probe_malloc failed\n",
- __func__));
- goto fail;
- }
+ /* Satisfy length-alignment requirements */
+ if (len & (ALIGNMENT - 1))
+ len = roundup(len, ALIGNMENT);
- if (!(brcmf_sdbrcm_probe_init(bus, card))) {
- BRCMF_ERROR(("%s: brcmf_sdbrcm_probe_init failed\n", __func__));
- goto fail;
- }
+ /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
- /* Register interrupt callback, but mask it (not operational yet). */
- BRCMF_INTR(("%s: disable SDIO interrupts (not interested yet)\n",
- __func__));
- brcmf_sdcard_intr_disable(card);
- ret = brcmf_sdcard_intr_reg(card, brcmf_sdbrcm_isr, bus);
- if (ret != 0) {
- BRCMF_ERROR(("%s: FAILED: sdcard_intr_reg returned %d\n",
- __func__, ret));
- goto fail;
- }
- BRCMF_INTR(("%s: registered SDIO interrupt function ok\n", __func__));
+ /* Need to lock here to protect txseq and SDIO tx calls */
+ down(&bus->sdsem);
- BRCMF_INFO(("%s: completed!!\n", __func__));
+ bus_wake(bus);
- /* if firmware path present try to download and bring up bus */
- ret = brcmf_bus_start(bus->drvr);
- if (ret != 0) {
- if (ret == -ENOLINK) {
- BRCMF_ERROR(("%s: dongle is not responding\n",
- __func__));
- goto fail;
- }
- }
- /* Ok, have the per-port tell the stack we're open for business */
- if (brcmf_net_attach(bus->drvr, 0) != 0) {
- BRCMF_ERROR(("%s: Net attach failed!!\n", __func__));
- goto fail;
- }
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- return bus;
+ /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
+ *(__le16 *) frame = cpu_to_le16((u16) msglen);
+ *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen);
-fail:
- brcmf_sdbrcm_release(bus);
- return NULL;
-}
+ /* Software tag: channel, sequence number, data offset */
+ swheader =
+ ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) &
+ SDPCM_CHANNEL_MASK)
+ | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) &
+ SDPCM_DOFFSET_MASK);
+ put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN);
+ put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
-static bool
-brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, void *card, u32 regsva,
- u16 devid)
-{
- u8 clkctl = 0;
- int err = 0;
+ if (!data_ok(bus)) {
+ brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
+ bus->tx_max, bus->tx_seq);
+ bus->ctrl_frame_stat = true;
+ /* Send from dpc */
+ bus->ctrl_frame_buf = frame;
+ bus->ctrl_frame_len = len;
- bus->alp_only = true;
+ brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
- /* Return the window to backplane enumeration space for core access */
- if (brcmf_sdbrcm_set_siaddr_window(bus, SI_ENUM_BASE))
- BRCMF_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n",
- __func__));
+ if (bus->ctrl_frame_stat == false) {
+ brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
+ ret = 0;
+ } else {
+ brcmf_dbg(INFO, "ctrl_frame_stat == true\n");
+ ret = -1;
+ }
+ }
+ if (ret == -1) {
#ifdef BCMDBG
- printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n",
- brcmf_sdcard_reg_read(bus->card, SI_ENUM_BASE, 4));
-
-#endif /* BCMDBG */
-
- /*
- * Force PLL off until brcmf_sdbrcm_chip_attach()
- * programs PLL control regs
- */
-
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
- BRCMF_INIT_CLKCTL1, &err);
- if (!err)
- clkctl =
- brcmf_sdcard_cfg_read(card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) {
+ printk(KERN_DEBUG "Tx Frame:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, len);
+ } else if (BRCMF_HDRS_ON()) {
+ printk(KERN_DEBUG "TxHdr:\n");
+ print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
+ frame, min_t(u16, len, 16));
+ }
+#endif
- if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
- BRCMF_ERROR(("brcmf_sdbrcm_probe: ChipClkCSR access: err %d"
- " wrote 0x%02x read 0x%02x\n",
- err, BRCMF_INIT_CLKCTL1, clkctl));
- goto fail;
+ do {
+ ret = brcmf_tx_frame(bus, frame, len);
+ } while (ret < 0 && retries++ < TXRETRIES);
}
- if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
- BRCMF_ERROR(("%s: brcmf_sdbrcm_chip_attach failed!\n",
- __func__));
- goto fail;
+ if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) {
+ bus->activity = false;
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
}
- if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
- BRCMF_ERROR(("%s: unsupported chip: 0x%04x\n",
- __func__, bus->ci->chip));
- goto fail;
- }
+ up(&bus->sdsem);
- brcmf_sdbrcm_sdiod_drive_strength_init(bus, brcmf_sdiod_drive_strength);
+ if (ret)
+ bus->drvr->tx_ctlerrs++;
+ else
+ bus->drvr->tx_ctlpkts++;
- /* Get info on the ARM and SOCRAM cores... */
- if (!BRCMF_NOPMU(bus)) {
- brcmf_sdcard_reg_read(bus->card,
- CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
- bus->orig_ramsize = bus->ci->ramsize;
- if (!(bus->orig_ramsize)) {
- BRCMF_ERROR(("%s: failed to find SOCRAM memory!\n",
- __func__));
- goto fail;
- }
- bus->ramsize = bus->orig_ramsize;
- if (brcmf_dongle_memsize)
- brcmf_sdbrcm_setmemsize(bus, brcmf_dongle_memsize);
+ return ret ? -EIO : 0;
+}
- BRCMF_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
- bus->ramsize, bus->orig_ramsize));
- }
+int
+brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen)
+{
+ int timeleft;
+ uint rxlen = 0;
+ bool pending;
- /* Set core control so an SDIO reset does a backplane reset */
- OR_REG(bus->ci->buscorebase + offsetof(struct sdpcmd_regs,
- corecontrol),
- CC_BPRESEN, u32);
+ brcmf_dbg(TRACE, "Enter\n");
- brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
+ /* Wait until control frame is available */
+ timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
- /* Locate an appropriately-aligned portion of hdrbuf */
- bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
- BRCMF_SDALIGN);
+ down(&bus->sdsem);
+ rxlen = bus->rxlen;
+ memcpy(msg, bus->rxctl, min(msglen, rxlen));
+ bus->rxlen = 0;
+ up(&bus->sdsem);
- /* Set the poll and/or interrupt flags */
- bus->intr = (bool) brcmf_intr;
- bus->poll = (bool) brcmf_poll;
- if (bus->poll)
- bus->pollrate = 1;
+ if (rxlen) {
+ brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
+ rxlen, msglen);
+ } else if (timeleft == 0) {
+ brcmf_dbg(ERROR, "resumed on timeout\n");
+ } else if (pending == true) {
+ brcmf_dbg(CTL, "cancelled\n");
+ return -ERESTARTSYS;
+ } else {
+ brcmf_dbg(CTL, "resumed for unknown reason?\n");
+ }
- return true;
+ if (rxlen)
+ bus->drvr->rx_ctlpkts++;
+ else
+ bus->drvr->rx_ctlerrs++;
-fail:
- return false;
+ return rxlen ? (int)rxlen : -ETIMEDOUT;
}
-static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus, void *card)
+static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len)
{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ int bcmerror = 0;
- if (bus->drvr->maxctl) {
- bus->rxblen =
- roundup((bus->drvr->maxctl + SDPCM_HDRLEN),
- ALIGNMENT) + BRCMF_SDALIGN;
- bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
- if (!(bus->rxbuf)) {
- BRCMF_ERROR(("%s: kmalloc of %d-byte rxbuf failed\n",
- __func__, bus->rxblen));
- goto fail;
- }
- }
+ brcmf_dbg(TRACE, "Enter\n");
- /* Allocate buffer to receive glomed packet */
- bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
- if (!(bus->databuf)) {
- BRCMF_ERROR(("%s: kmalloc of %d-byte databuf failed\n",
- __func__, MAX_DATA_BUF));
- /* release rxbuf which was already located as above */
- if (!bus->rxblen)
- kfree(bus->rxbuf);
- goto fail;
+ /* Basic sanity checks */
+ if (bus->drvr->up) {
+ bcmerror = -EISCONN;
+ goto err;
+ }
+ if (!len) {
+ bcmerror = -EOVERFLOW;
+ goto err;
}
- /* Align the buffer */
- if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
- bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
- ((unsigned long)bus->databuf % BRCMF_SDALIGN));
- else
- bus->dataptr = bus->databuf;
+ /* Free the old ones and replace with passed variables */
+ kfree(bus->vars);
- return true;
+ bus->vars = kmalloc(len, GFP_ATOMIC);
+ bus->varsz = bus->vars ? len : 0;
+ if (bus->vars == NULL) {
+ bcmerror = -ENOMEM;
+ goto err;
+ }
-fail:
- return false;
+ /* Copy the passed variables, which should include the
+ terminating double-null */
+ memcpy(bus->vars, arg, bus->varsz);
+err:
+ return bcmerror;
}
-static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus, void *card)
+static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
{
- s32 fnum;
+ int bcmerror = 0;
+ u32 varsize;
+ u32 varaddr;
+ u8 *vbuffer;
+ u32 varsizew;
+ __le32 varsizew_le;
+#ifdef BCMDBG
+ char *nvram_ularray;
+#endif /* BCMDBG */
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ /* Even if there are no vars are to be written, we still
+ need to set the ramsize. */
+ varsize = bus->varsz ? roundup(bus->varsz, 4) : 0;
+ varaddr = (bus->ramsize - 4) - varsize;
-#ifdef SDTEST
- brcmf_sdbrcm_pktgen_init(bus);
-#endif /* SDTEST */
+ if (bus->vars) {
+ vbuffer = kzalloc(varsize, GFP_ATOMIC);
+ if (!vbuffer)
+ return -ENOMEM;
- /* Disable F2 to clear any intermediate frame state on the dongle */
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
+ memcpy(vbuffer, bus->vars, bus->varsz);
- bus->drvr->busstate = BRCMF_BUS_DOWN;
- bus->sleeping = false;
- bus->rxflow = false;
+ /* Write the vars list */
+ bcmerror =
+ brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize);
+#ifdef BCMDBG
+ /* Verify NVRAM bytes */
+ brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize);
+ nvram_ularray = kmalloc(varsize, GFP_ATOMIC);
+ if (!nvram_ularray)
+ return -ENOMEM;
- /* Done with backplane-dependent accesses, can drop clock... */
- brcmf_sdcard_cfg_write(card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0,
- NULL);
+ /* Upload image to verify downloaded contents. */
+ memset(nvram_ularray, 0xaa, varsize);
- /* ...and initialize clock/power states */
- bus->clkstate = CLK_SDONLY;
- bus->idletime = (s32) brcmf_idletime;
- bus->idleclock = BRCMF_IDLE_ACTIVE;
+ /* Read the vars list to temp buffer for comparison */
+ bcmerror =
+ brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray,
+ varsize);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n",
+ bcmerror, varsize, varaddr);
+ }
+ /* Compare the org NVRAM with the one read from RAM */
+ if (memcmp(vbuffer, nvram_ularray, varsize))
+ brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n");
+ else
+ brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n");
- /* Query the F2 block size, set roundup accordingly */
- fnum = 2;
- if (brcmf_sdcard_iovar_op(card, "sd_blocksize", &fnum, sizeof(s32),
- &bus->blocksize, sizeof(s32), false) != 0) {
- bus->blocksize = 0;
- BRCMF_ERROR(("%s: fail on %s get\n", __func__, "sd_blocksize"));
- } else {
- BRCMF_INFO(("%s: Initial value for %s is %d\n",
- __func__, "sd_blocksize", bus->blocksize));
+ kfree(nvram_ularray);
+#endif /* BCMDBG */
+
+ kfree(vbuffer);
}
- bus->roundup = min(max_roundup, bus->blocksize);
- /* Query if bus module supports packet chaining,
- default to use if supported */
- if (brcmf_sdcard_iovar_op(card, "sd_rxchain", NULL, 0,
- &bus->sd_rxchain, sizeof(s32),
- false) != 0) {
- bus->sd_rxchain = false;
+ /* adjust to the user specified RAM */
+ brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize);
+ brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n",
+ varaddr, varsize);
+ varsize = ((bus->ramsize - 4) - varaddr);
+
+ /*
+ * Determine the length token:
+ * Varsize, converted to words, in lower 16-bits, checksum
+ * in upper 16-bits.
+ */
+ if (bcmerror) {
+ varsizew = 0;
+ varsizew_le = cpu_to_le32(0);
} else {
- BRCMF_INFO(("%s: bus module (through sdiocard API) %s"
- " chaining\n", __func__, bus->sd_rxchain
- ? "supports" : "does not support"));
+ varsizew = varsize / 4;
+ varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
+ varsizew_le = cpu_to_le32(varsizew);
}
- bus->use_rxchain = (bool) bus->sd_rxchain;
- return true;
-}
+ brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n",
+ varsize, varsizew);
-static bool
-brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus, void *card)
-{
- bool ret;
+ /* Write the length token to the last word */
+ bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4),
+ (u8 *)&varsizew_le, 4);
- /* Download the firmware */
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ return bcmerror;
+}
- ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
+static void
+brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
+{
+ u32 regdata;
- brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ if (regdata & SBTML_RESET)
+ return;
- return ret;
-}
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
+ /*
+ * set target reject and spin until busy is clear
+ * (preserve core-specific bits)
+ */
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
+ 4, regdata | SBTML_REJ);
-/* Detach and free everything */
-static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
-{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ udelay(1);
+ SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4) &
+ SBTMH_BUSY), 100000);
- if (bus) {
- /* De-register interrupt handler */
- brcmf_sdcard_intr_disable(bus->card);
- brcmf_sdcard_intr_dereg(bus->card);
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4);
+ if (regdata & SBTMH_BUSY)
+ brcmf_dbg(ERROR, "ARM core still busy\n");
- if (bus->drvr) {
- brcmf_detach(bus->drvr);
- brcmf_sdbrcm_release_dongle(bus);
- bus->drvr = NULL;
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbidlow), 4);
+ if (regdata & SBIDL_INIT) {
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) |
+ SBIM_RJ;
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbimstate), 4,
+ regdata);
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4);
+ udelay(1);
+ SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) &
+ SBIM_BY), 100000);
}
- brcmf_sdbrcm_release_malloc(bus);
+ /* set reset and reject while enabling the clocks */
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4,
+ (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+ SBTML_REJ | SBTML_RESET));
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatelow), 4);
+ udelay(10);
- kfree(bus);
+ /* clear the initiator reject bit */
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbidlow), 4);
+ if (regdata & SBIDL_INIT) {
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4) &
+ ~SBIM_RJ;
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbimstate), 4,
+ regdata);
+ }
}
- BRCMF_TRACE(("%s: Disconnected\n", __func__));
+ /* leave reset and reject asserted */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SBTML_REJ | SBTML_RESET));
+ udelay(1);
}
-static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
+static void
+brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
{
- BRCMF_TRACE(("%s: Enter\n", __func__));
-
- if (bus->drvr && bus->drvr->dongle_reset)
- return;
+ u32 regdata;
- kfree(bus->rxbuf);
- bus->rxctl = bus->rxbuf = NULL;
- bus->rxlen = 0;
+ /*
+ * Must do the disable sequence first to work for
+ * arbitrary current core state.
+ */
+ brcmf_sdbrcm_chip_disablecore(sdiodev, corebase);
- kfree(bus->databuf);
- bus->databuf = NULL;
-}
+ /*
+ * Now do the initialization sequence.
+ * set reset while enabling the clock and
+ * forcing them on throughout the core
+ */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
+ SBTML_RESET);
+ udelay(1);
-static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
-{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4);
+ if (regdata & SBTMH_SERR)
+ brcmf_sdcard_reg_write(sdiodev,
+ CORE_SB(corebase, sbtmstatehigh), 4, 0);
- if (bus->drvr && bus->drvr->dongle_reset)
- return;
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(corebase, sbimstate), 4);
+ if (regdata & (SBIM_IBE | SBIM_TO))
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
+ regdata & ~(SBIM_IBE | SBIM_TO));
- if (bus->ci) {
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
- brcmf_sdbrcm_chip_detach(bus);
- if (bus->vars && bus->varsz)
- kfree(bus->vars);
- bus->vars = NULL;
- }
+ /* clear reset and allow it to propagate throughout the core */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SICF_FGC << SBTML_SICF_SHIFT) |
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ udelay(1);
- BRCMF_TRACE(("%s: Disconnected\n", __func__));
+ /* leave clock enabled */
+ brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ udelay(1);
}
-static void brcmf_sdbrcm_disconnect(void *ptr)
+static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
{
- struct brcmf_bus *bus = (struct brcmf_bus *)ptr;
-
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ uint retries;
+ u32 regdata;
+ int bcmerror = 0;
- if (bus) {
- brcmf_sdbrcm_release(bus);
- }
+ /* To enter download state, disable ARM and reset SOCRAM.
+ * To exit download state, simply reset ARM (default is RAM boot).
+ */
+ if (enter) {
+ bus->alp_only = true;
- BRCMF_TRACE(("%s: Disconnected\n", __func__));
-}
+ brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
+ bus->ci->armcorebase);
-/* Register/Unregister functions are called by the main DHD entry
- * point (e.g. module insertion) to link with the bus driver, in
- * order to look for or await the device.
- */
+ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
-static struct brcmf_sdioh_driver brcmf_sdio = {
- brcmf_sdbrcm_probe,
- brcmf_sdbrcm_disconnect
-};
+ /* Clear the top bit of memory */
+ if (bus->ramsize) {
+ u32 zeros = 0;
+ brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4,
+ (u8 *)&zeros, 4);
+ }
+ } else {
+ regdata = brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
+ regdata &= (SBTML_RESET | SBTML_REJ_MASK |
+ (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
+ if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
+ brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
+ bcmerror = -EBADE;
+ goto fail;
+ }
-int brcmf_bus_register(void)
-{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ bcmerror = brcmf_sdbrcm_write_vars(bus);
+ if (bcmerror) {
+ brcmf_dbg(ERROR, "no vars written to RAM\n");
+ bcmerror = 0;
+ }
- /* Sanity check on the module parameters */
- do {
- /* Both watchdog and DPC as tasklets are ok */
- if ((brcmf_watchdog_prio < 0) && (brcmf_dpc_prio < 0))
- break;
+ w_sdreg32(bus, 0xFFFFFFFF,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
- /* If both watchdog and DPC are threads, TX must be deferred */
- if ((brcmf_watchdog_prio >= 0) && (brcmf_dpc_prio >= 0)
- && brcmf_deferred_tx)
- break;
+ brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
- BRCMF_ERROR(("Invalid module parameters.\n"));
- return -EINVAL;
- } while (0);
+ /* Allow HT Clock now that the ARM is running. */
+ bus->alp_only = false;
- return brcmf_sdio_register(&brcmf_sdio);
+ bus->drvr->busstate = BRCMF_BUS_LOAD;
+ }
+fail:
+ return bcmerror;
}
-void brcmf_bus_unregister(void)
+static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ if (bus->firmware->size < bus->fw_ptr + len)
+ len = bus->firmware->size - bus->fw_ptr;
- brcmf_sdio_unregister();
+ memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
+ bus->fw_ptr += len;
+ return len;
}
+MODULE_FIRMWARE(BCM4329_FW_NAME);
+MODULE_FIRMWARE(BCM4329_NV_NAME);
+
static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
{
int offset = 0;
@@ -5916,22 +3408,19 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
u8 *memblock = NULL, *memptr;
int ret;
- BRCMF_INFO(("%s: Enter\n", __func__));
+ brcmf_dbg(INFO, "Enter\n");
bus->fw_name = BCM4329_FW_NAME;
ret = request_firmware(&bus->firmware, bus->fw_name,
- &gInstance->func[2]->dev);
+ &bus->sdiodev->func[2]->dev);
if (ret) {
- BRCMF_ERROR(("%s: Fail to request firmware %d\n",
- __func__, ret));
+ brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret);
return ret;
}
bus->fw_ptr = 0;
memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
if (memblock == NULL) {
- BRCMF_ERROR(("%s: Failed to allocate memory %d bytes\n",
- __func__, MEMBLOCK));
ret = -ENOMEM;
goto err;
}
@@ -5944,9 +3433,8 @@ static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus)
brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) {
ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len);
if (ret) {
- BRCMF_ERROR(("%s: error %d on writing %d membytes at "
- "0x%08x\n", __func__, ret, MEMBLOCK,
- offset));
+ brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n",
+ ret, MEMBLOCK, offset);
goto err;
}
@@ -6022,17 +3510,15 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
bus->nv_name = BCM4329_NV_NAME;
ret = request_firmware(&bus->firmware, bus->nv_name,
- &gInstance->func[2]->dev);
+ &bus->sdiodev->func[2]->dev);
if (ret) {
- BRCMF_ERROR(("%s: Fail to request nvram %d\n", __func__, ret));
+ brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret);
return ret;
}
bus->fw_ptr = 0;
memblock = kmalloc(MEMBLOCK, GFP_ATOMIC);
if (memblock == NULL) {
- BRCMF_ERROR(("%s: Failed to allocate memory %d bytes\n",
- __func__, MEMBLOCK));
ret = -ENOMEM;
goto err;
}
@@ -6048,11 +3534,9 @@ static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus)
if (len)
ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1);
if (ret)
- BRCMF_ERROR(("%s: error downloading vars: %d\n",
- __func__, ret));
+ brcmf_dbg(ERROR, "error downloading vars: %d\n", ret);
} else {
- BRCMF_ERROR(("%s: error reading nvram file: %d\n",
- __func__, len));
+ brcmf_dbg(ERROR, "error reading nvram file: %d\n", len);
ret = -EIO;
}
@@ -6071,28 +3555,23 @@ static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
/* Keep arm in reset */
if (brcmf_sdbrcm_download_state(bus, true)) {
- BRCMF_ERROR(("%s: error placing ARM core in reset\n",
- __func__));
+ brcmf_dbg(ERROR, "error placing ARM core in reset\n");
goto err;
}
/* External image takes precedence if specified */
if (brcmf_sdbrcm_download_code_file(bus)) {
- BRCMF_ERROR(("%s: dongle image file download failed\n",
- __func__));
+ brcmf_dbg(ERROR, "dongle image file download failed\n");
goto err;
}
/* External nvram takes precedence if specified */
- if (brcmf_sdbrcm_download_nvram(bus)) {
- BRCMF_ERROR(("%s: dongle nvram file download failed\n",
- __func__));
- }
+ if (brcmf_sdbrcm_download_nvram(bus))
+ brcmf_dbg(ERROR, "dongle nvram file download failed\n");
/* Take arm out of reset */
if (brcmf_sdbrcm_download_state(bus, false)) {
- BRCMF_ERROR(("%s: error getting out of ARM core reset\n",
- __func__));
+ brcmf_dbg(ERROR, "error getting out of ARM core reset\n");
goto err;
}
@@ -6102,359 +3581,379 @@ err:
return bcmerror;
}
-
-static int
-brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags,
- u8 *buf, uint nbytes, struct sk_buff *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle)
+static bool
+brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus)
{
- return brcmf_sdcard_send_buf
- (bus->card, addr, fn, flags, buf, nbytes, pkt, complete,
- handle);
+ bool ret;
+
+ /* Download the firmware */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+
+ ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
+
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+
+ return ret;
}
-int brcmf_bus_devreset(struct brcmf_pub *drvr, u8 flag)
+void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
{
- int bcmerror = 0;
- struct brcmf_bus *bus;
-
- bus = drvr->bus;
+ u32 local_hostintmask;
+ u8 saveclk;
+ uint retries;
+ int err;
- if (flag == true) {
- brcmf_sdbrcm_wd_timer(bus, 0);
- if (!bus->drvr->dongle_reset) {
- /* Expect app to have torn down any
- connection before calling */
- /* Stop the bus, disable F2 */
- brcmf_sdbrcm_bus_stop(bus, false);
-
- /* Clean tx/rx buffer pointers,
- detach from the dongle */
- brcmf_sdbrcm_release_dongle(bus);
+ brcmf_dbg(TRACE, "Enter\n");
- bus->drvr->dongle_reset = true;
- bus->drvr->up = false;
+ if (bus->watchdog_tsk) {
+ send_sig(SIGTERM, bus->watchdog_tsk, 1);
+ kthread_stop(bus->watchdog_tsk);
+ bus->watchdog_tsk = NULL;
+ }
- BRCMF_TRACE(("%s: WLAN OFF DONE\n", __func__));
- /* App can now remove power from device */
- } else
- bcmerror = -EIO;
- } else {
- /* App must have restored power to device before calling */
-
- BRCMF_TRACE(("\n\n%s: == WLAN ON ==\n", __func__));
-
- if (bus->drvr->dongle_reset) {
- /* Turn on WLAN */
-
- /* Attempt to re-attach & download */
- if (brcmf_sdbrcm_probe_attach(bus, bus->card,
- SI_ENUM_BASE,
- bus->cl_devid)) {
- /* Attempt to download binary to the dongle */
- if (brcmf_sdbrcm_probe_init(bus, bus->card)) {
- /* Re-init bus, enable F2 transfer */
- brcmf_sdbrcm_bus_init(bus->drvr, false);
-
- bus->drvr->dongle_reset = false;
- bus->drvr->up = true;
-
- BRCMF_TRACE(("%s: WLAN ON DONE\n",
- __func__));
- } else
- bcmerror = -EIO;
- } else
- bcmerror = -EIO;
- } else {
- bcmerror = -EISCONN;
- BRCMF_ERROR(("%s: Set DEVRESET=false invoked when"
- " device is on\n", __func__));
- bcmerror = -EIO;
- }
- brcmf_sdbrcm_wd_timer(bus, brcmf_watchdog_ms);
+ if (bus->dpc_tsk && bus->dpc_tsk != current) {
+ send_sig(SIGTERM, bus->dpc_tsk, 1);
+ kthread_stop(bus->dpc_tsk);
+ bus->dpc_tsk = NULL;
}
- return bcmerror;
-}
-static int
-brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_card *card,
- struct chip_info *ci, u32 regs)
-{
- u32 regdata;
+ down(&bus->sdsem);
- /*
- * Get CC core rev
- * Chipid is assume to be at offset 0 from regs arg
- * For different chiptypes or old sdio hosts w/o chipcommon,
- * other ways of recognition should be added here.
- */
- ci->cccorebase = regs;
- regdata = brcmf_sdcard_reg_read(card,
- CORE_CC_REG(ci->cccorebase, chipid), 4);
- ci->chip = regdata & CID_ID_MASK;
- ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+ bus_wake(bus);
- BRCMF_INFO(("%s: chipid=0x%x chiprev=%d\n",
- __func__, ci->chip, ci->chiprev));
+ /* Enable clock for device interrupts */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
- /* Address of cores for new chips should be added here */
- switch (ci->chip) {
- case BCM4329_CHIP_ID:
- ci->buscorebase = BCM4329_CORE_BUS_BASE;
- ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
- ci->armcorebase = BCM4329_CORE_ARM_BASE;
- ci->ramsize = BCM4329_RAMSIZE;
- break;
- default:
- BRCMF_ERROR(("%s: chipid 0x%x is not supported\n",
- __func__, ci->chip));
- return -ENODEV;
+ /* Disable and clear interrupts at the chip level also */
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
+ local_hostintmask = bus->hostintmask;
+ bus->hostintmask = 0;
+
+ /* Change our idea of bus state */
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
}
+ if (err)
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(ci->cccorebase, sbidhigh), 4);
- ci->ccrev = SBCOREREV(regdata);
+ /* Turn off the bus (F2), free any pending packets */
+ brcmf_dbg(INTR, "disable SDIO interrupts\n");
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
- regdata = brcmf_sdcard_reg_read(card,
- CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
- ci->pmurev = regdata & PCAP_REV_MASK;
+ /* Clear any pending interrupts now that F2 is disabled */
+ w_sdreg32(bus, local_hostintmask,
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(ci->buscorebase, sbidhigh), 4);
- ci->buscorerev = SBCOREREV(regdata);
- ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
+ /* Turn off the backplane clock (only) */
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
- BRCMF_INFO(("%s: ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
- __func__, ci->ccrev, ci->pmurev,
- ci->buscorerev, ci->buscoretype));
+ /* Clear the data packet queues */
+ brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
- /* get chipcommon capabilites */
- ci->cccaps = brcmf_sdcard_reg_read(card,
- CORE_CC_REG(ci->cccorebase, capabilities), 4);
+ /* Clear any held glomming stuff */
+ if (bus->glomd)
+ brcmu_pkt_buf_free_skb(bus->glomd);
- return 0;
+ if (bus->glom)
+ brcmu_pkt_buf_free_skb(bus->glom);
+
+ bus->glom = bus->glomd = NULL;
+
+ /* Clear rx control and wake any waiters */
+ bus->rxlen = 0;
+ brcmf_sdbrcm_dcmd_resp_wake(bus);
+
+ /* Reset some F2 state stuff */
+ bus->rxskip = false;
+ bus->tx_seq = bus->rx_seq = 0;
+
+ up(&bus->sdsem);
}
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_card *card, u32 corebase)
+int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr)
{
- u32 regdata;
+ struct brcmf_bus *bus = drvr->bus;
+ unsigned long timeout;
+ uint retries = 0;
+ u8 ready, enable;
+ int err, ret = 0;
+ u8 saveclk;
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatelow), 4);
- if (regdata & SBTML_RESET)
- return;
+ brcmf_dbg(TRACE, "Enter\n");
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatelow), 4);
- if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
- /*
- * set target reject and spin until busy is clear
- * (preserve core-specific bits)
- */
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatelow), 4);
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4,
- regdata | SBTML_REJ);
+ /* try to download image and nvram to the dongle */
+ if (drvr->busstate == BRCMF_BUS_DOWN) {
+ if (!(brcmf_sdbrcm_download_firmware(bus)))
+ return -1;
+ }
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatelow), 4);
- udelay(1);
- SPINWAIT((brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatehigh), 4) &
- SBTMH_BUSY), 100000);
+ if (!bus->drvr)
+ return 0;
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatehigh), 4);
- if (regdata & SBTMH_BUSY)
- BRCMF_ERROR(("%s: ARM core still busy\n", __func__));
+ /* Start the watchdog timer */
+ bus->drvr->tickcnt = 0;
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbidlow), 4);
- if (regdata & SBIDL_INIT) {
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbimstate), 4) |
- SBIM_RJ;
- brcmf_sdcard_reg_write(card,
- CORE_SB(corebase, sbimstate), 4,
- regdata);
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbimstate), 4);
- udelay(1);
- SPINWAIT((brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbimstate), 4) &
- SBIM_BY), 100000);
- }
+ down(&bus->sdsem);
- /* set reset and reject while enabling the clocks */
- brcmf_sdcard_reg_write(card,
- CORE_SB(corebase, sbtmstatelow), 4,
- (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
- SBTML_REJ | SBTML_RESET));
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbtmstatelow), 4);
- udelay(10);
+ /* Make sure backplane clock is on, needed to generate F2 interrupt */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (bus->clkstate != CLK_AVAIL)
+ goto exit;
- /* clear the initiator reject bit */
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbidlow), 4);
- if (regdata & SBIDL_INIT) {
- regdata = brcmf_sdcard_reg_read(card,
- CORE_SB(corebase, sbimstate), 4) &
- ~SBIM_RJ;
- brcmf_sdcard_reg_write(card,
- CORE_SB(corebase, sbimstate), 4,
- regdata);
- }
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
+ saveclk =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ if (!err) {
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
+ }
+ if (err) {
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
+ goto exit;
}
- /* leave reset and reject asserted */
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4,
- (SBTML_REJ | SBTML_RESET));
- udelay(1);
+ /* Enable function 2 (frame transfers) */
+ w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
+ offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
+ enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ enable, NULL);
+
+ timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
+ ready = 0;
+ while (enable != ready) {
+ ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
+ SDIO_CCCR_IORx, NULL);
+ if (time_after(jiffies, timeout))
+ break;
+ else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
+ /* prevent busy waiting if it takes too long */
+ msleep_interruptible(20);
+ }
+
+ brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready);
+
+ /* If F2 successfully enabled, set core and enable interrupts */
+ if (ready == enable) {
+ /* Set up the interrupt mask and enable interrupts */
+ bus->hostintmask = HOSTINTMASK;
+ w_sdreg32(bus, bus->hostintmask,
+ offsetof(struct sdpcmd_regs, hostintmask), &retries);
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_WATERMARK, 8, &err);
+
+ /* Set bus state according to enable result */
+ drvr->busstate = BRCMF_BUS_DATA;
+ }
+
+ else {
+ /* Disable F2 again */
+ enable = SDIO_FUNC_ENABLE_1;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
+ SDIO_CCCR_IOEx, enable, NULL);
+ }
+
+ /* Restore previous clock setting */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
+
+ /* If we didn't come up, turn off backplane clock */
+ if (drvr->busstate != BRCMF_BUS_DATA)
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+
+exit:
+ up(&bus->sdsem);
+
+ return ret;
}
-static int
-brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs)
+void brcmf_sdbrcm_isr(void *arg)
{
- struct chip_info *ci;
- int err;
- u8 clkval, clkset;
+ struct brcmf_bus *bus = (struct brcmf_bus *) arg;
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ brcmf_dbg(TRACE, "Enter\n");
- /* alloc chip_info_t */
- ci = kmalloc(sizeof(struct chip_info), GFP_ATOMIC);
- if (NULL == ci) {
- BRCMF_ERROR(("%s: malloc failed!\n", __func__));
- return -ENOMEM;
+ if (!bus) {
+ brcmf_dbg(ERROR, "bus is null pointer, exiting\n");
+ return;
}
- memset((unsigned char *)ci, 0, sizeof(struct chip_info));
-
- /* bus/core/clk setup for register access */
- /* Try forcing SDIO core to do ALPAvail request only */
- clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
- clkset, &err);
- if (err) {
- BRCMF_ERROR(("%s: error writing for HT off\n", __func__));
- goto fail;
+ if (bus->drvr->busstate == BRCMF_BUS_DOWN) {
+ brcmf_dbg(ERROR, "bus is down. we have nothing to do\n");
+ return;
}
+ /* Count the interrupt call */
+ bus->intrcount++;
+ bus->ipend = true;
- /* If register supported, wait for ALPAvail and then force ALP */
- /* This may take up to 15 milliseconds */
- clkval = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL);
- if ((clkval & ~SBSDIO_AVBITS) == clkset) {
- SPINWAIT(((clkval =
- brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- NULL)),
- !SBSDIO_ALPAV(clkval)),
- PMU_MAX_TRANSITION_DLY);
- if (!SBSDIO_ALPAV(clkval)) {
- BRCMF_ERROR(("%s: timeout on ALPAV wait,"
- " clkval 0x%02x\n", __func__, clkval));
- err = -EBUSY;
- goto fail;
- }
- clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
- SBSDIO_FORCE_ALP;
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- clkset, &err);
- udelay(65);
- } else {
- BRCMF_ERROR(("%s: ChipClkCSR access: wrote 0x%02x"
- " read 0x%02x\n", __func__, clkset, clkval));
- err = -EACCES;
- goto fail;
+ /* Shouldn't get this interrupt if we're sleeping? */
+ if (bus->sleeping) {
+ brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n");
+ return;
}
- /* Also, disable the extra SDIO pull-ups */
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP,
- 0, NULL);
+ /* Disable additional interrupts (is this needed now)? */
+ if (!bus->intr)
+ brcmf_dbg(ERROR, "isr w/o interrupt configured!\n");
- err = brcmf_sdbrcm_chip_recognition(bus->card, ci, regs);
- if (err)
- goto fail;
+#if defined(ISR_THREAD)
+ while (brcmf_sdbrcm_dpc(bus))
+ ;
+#else
+ bus->dpc_sched = true;
+ if (bus->dpc_tsk)
+ complete(&bus->dpc_wait);
+#endif
- /*
- * Make sure any on-chip ARM is off (in case strapping is wrong),
- * or downloaded code was already running.
- */
- brcmf_sdbrcm_chip_disablecore(bus->card, ci->armcorebase);
+}
- brcmf_sdcard_reg_write(bus->card,
- CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
- brcmf_sdcard_reg_write(bus->card,
- CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
+static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr)
+{
+ struct brcmf_bus *bus;
- /* Disable F2 to clear any intermediate frame state on the dongle */
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
+ brcmf_dbg(TIMER, "Enter\n");
- /* WAR: cmd52 backplane read so core HW will drop ALPReq */
- clkval = brcmf_sdcard_cfg_read(bus->card, SDIO_FUNC_1,
- 0, NULL);
+ bus = drvr->bus;
- /* Done with backplane-dependent accesses, can drop clock... */
- brcmf_sdcard_cfg_write(bus->card, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
- 0, NULL);
+ /* Ignore the timer if simulating bus down */
+ if (bus->sleeping)
+ return false;
- bus->ci = ci;
- return 0;
-fail:
- bus->ci = NULL;
- kfree(ci);
- return err;
+ down(&bus->sdsem);
+
+ /* Poll period: check device if appropriate. */
+ if (bus->poll && (++bus->polltick >= bus->pollrate)) {
+ u32 intstatus = 0;
+
+ /* Reset poll tick */
+ bus->polltick = 0;
+
+ /* Check device if no interrupts */
+ if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
+
+ if (!bus->dpc_sched) {
+ u8 devpend;
+ devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
+ SDIO_FUNC_0, SDIO_CCCR_INTx,
+ NULL);
+ intstatus =
+ devpend & (INTR_STATUS_FUNC1 |
+ INTR_STATUS_FUNC2);
+ }
+
+ /* If there is something, make like the ISR and
+ schedule the DPC */
+ if (intstatus) {
+ bus->pollcnt++;
+ bus->ipend = true;
+
+ bus->dpc_sched = true;
+ if (bus->dpc_tsk)
+ complete(&bus->dpc_wait);
+ }
+ }
+
+ /* Update interrupt tracking */
+ bus->lastintrs = bus->intrcount;
+ }
+#ifdef BCMDBG
+ /* Poll for console output periodically */
+ if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) {
+ bus->console.count += BRCMF_WD_POLL_MS;
+ if (bus->console.count >= bus->console_interval) {
+ bus->console.count -= bus->console_interval;
+ /* Make sure backplane clock is on */
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ if (brcmf_sdbrcm_readconsole(bus) < 0)
+ /* stop on error */
+ bus->console_interval = 0;
+ }
+ }
+#endif /* BCMDBG */
+
+ /* On idle timeout clear activity flag and/or turn off clock */
+ if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
+ if (++bus->idlecount >= bus->idletime) {
+ bus->idlecount = 0;
+ if (bus->activity) {
+ bus->activity = false;
+ brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
+ } else {
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ }
+ }
+ }
+
+ up(&bus->sdsem);
+
+ return bus->ipend;
}
-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_card *card, u32 corebase)
+static bool brcmf_sdbrcm_chipmatch(u16 chipid)
{
- u32 regdata;
+ if (chipid == BCM4329_CHIP_ID)
+ return true;
+ return false;
+}
- /*
- * Must do the disable sequence first to work for
- * arbitrary current core state.
- */
- brcmf_sdbrcm_chip_disablecore(card, corebase);
+static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
- /*
- * Now do the initialization sequence.
- * set reset while enabling the clock and
- * forcing them on throughout the core
- */
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4,
- ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
- SBTML_RESET);
- udelay(1);
+ kfree(bus->rxbuf);
+ bus->rxctl = bus->rxbuf = NULL;
+ bus->rxlen = 0;
- regdata = brcmf_sdcard_reg_read(card, CORE_SB(corebase, sbtmstatehigh),
- 4);
- if (regdata & SBTMH_SERR)
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatehigh),
- 4, 0);
+ kfree(bus->databuf);
+ bus->databuf = NULL;
+}
- regdata = brcmf_sdcard_reg_read(card, CORE_SB(corebase, sbimstate), 4);
- if (regdata & (SBIM_IBE | SBIM_TO))
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbimstate), 4,
- regdata & ~(SBIM_IBE | SBIM_TO));
+static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
- /* clear reset and allow it to propagate throughout the core */
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4,
- (SICF_FGC << SBTML_SICF_SHIFT) |
- (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
- udelay(1);
+ if (bus->drvr->maxctl) {
+ bus->rxblen =
+ roundup((bus->drvr->maxctl + SDPCM_HDRLEN),
+ ALIGNMENT) + BRCMF_SDALIGN;
+ bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
+ if (!(bus->rxbuf))
+ goto fail;
+ }
- /* leave clock enabled */
- brcmf_sdcard_reg_write(card, CORE_SB(corebase, sbtmstatelow), 4,
- (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
- udelay(1);
+ /* Allocate buffer to receive glomed packet */
+ bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC);
+ if (!(bus->databuf)) {
+ /* release rxbuf which was already located as above */
+ if (!bus->rxblen)
+ kfree(bus->rxbuf);
+ goto fail;
+ }
+
+ /* Align the buffer */
+ if ((unsigned long)bus->databuf % BRCMF_SDALIGN)
+ bus->dataptr = bus->databuf + (BRCMF_SDALIGN -
+ ((unsigned long)bus->databuf % BRCMF_SDALIGN));
+ else
+ bus->dataptr = bus->databuf;
+
+ return true;
+
+fail:
+ return false;
}
/* SDIO Pad drive strength to select value mappings */
@@ -6499,8 +3998,17 @@ static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
-static void
-brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, u32 drivestrength) {
+static char *brcmf_chipname(uint chipid, char *buf, uint len)
+{
+ const char *fmt;
+
+ fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+ snprintf(buf, len, fmt, chipid);
+ return buf;
+}
+
+static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
+ u32 drivestrength) {
struct sdiod_drive_str *str_tab = NULL;
u32 str_mask = 0;
u32 str_shift = 0;
@@ -6527,10 +4035,9 @@ brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, u32 drivestrength)
str_shift = 11;
break;
default:
- BRCMF_ERROR(("No SDIO Drive strength init"
- "done for chip %s rev %d pmurev %d\n",
- brcmu_chipname(bus->ci->chip, chn, 8),
- bus->ci->chiprev, bus->ci->pmurev));
+ brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+ brcmf_chipname(bus->ci->chip, chn, 8),
+ bus->ci->chiprev, bus->ci->pmurev);
break;
}
@@ -6546,48 +4053,287 @@ brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, u32 drivestrength)
}
}
- brcmf_sdcard_reg_write(bus->card,
+ brcmf_sdcard_reg_write(bus->sdiodev,
CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
4, 1);
- cc_data_temp = brcmf_sdcard_reg_read(bus->card,
+ cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
- brcmf_sdcard_reg_write(bus->card,
+ brcmf_sdcard_reg_write(bus->sdiodev,
CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
4, cc_data_temp);
- BRCMF_INFO(("SDIO: %dmA drive strength selected, "
- "set to 0x%08x\n", drivestrength, cc_data_temp));
+ brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
+ drivestrength, cc_data_temp);
}
}
-static void
-brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
+static int
+brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev,
+ struct chip_info *ci, u32 regs)
{
- BRCMF_TRACE(("%s: Enter\n", __func__));
+ u32 regdata;
- kfree(bus->ci);
+ /*
+ * Get CC core rev
+ * Chipid is assume to be at offset 0 from regs arg
+ * For different chiptypes or old sdio hosts w/o chipcommon,
+ * other ways of recognition should be added here.
+ */
+ ci->cccorebase = regs;
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, chipid), 4);
+ ci->chip = regdata & CID_ID_MASK;
+ ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+
+ brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
+
+ /* Address of cores for new chips should be added here */
+ switch (ci->chip) {
+ case BCM4329_CHIP_ID:
+ ci->buscorebase = BCM4329_CORE_BUS_BASE;
+ ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
+ ci->armcorebase = BCM4329_CORE_ARM_BASE;
+ ci->ramsize = BCM4329_RAMSIZE;
+ break;
+ default:
+ brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
+ return -ENODEV;
+ }
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(ci->cccorebase, sbidhigh), 4);
+ ci->ccrev = SBCOREREV(regdata);
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
+ ci->pmurev = regdata & PCAP_REV_MASK;
+
+ regdata = brcmf_sdcard_reg_read(sdiodev,
+ CORE_SB(ci->buscorebase, sbidhigh), 4);
+ ci->buscorerev = SBCOREREV(regdata);
+ ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
+
+ brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+ ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
+
+ /* get chipcommon capabilites */
+ ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
+ CORE_CC_REG(ci->cccorebase, capabilities), 4);
+
+ return 0;
+}
+
+static int
+brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs)
+{
+ struct chip_info *ci;
+ int err;
+ u8 clkval, clkset;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* alloc chip_info_t */
+ ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
+ if (NULL == ci)
+ return -ENOMEM;
+
+ /* bus/core/clk setup for register access */
+ /* Try forcing SDIO core to do ALPAvail request only */
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ if (err) {
+ brcmf_dbg(ERROR, "error writing for HT off\n");
+ goto fail;
+ }
+
+ /* If register supported, wait for ALPAvail and then force ALP */
+ /* This may take up to 15 milliseconds */
+ clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+ if ((clkval & ~SBSDIO_AVBITS) == clkset) {
+ SPINWAIT(((clkval =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ NULL)),
+ !SBSDIO_ALPAV(clkval)),
+ PMU_MAX_TRANSITION_DLY);
+ if (!SBSDIO_ALPAV(clkval)) {
+ brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
+ clkval);
+ err = -EBUSY;
+ goto fail;
+ }
+ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
+ SBSDIO_FORCE_ALP;
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ clkset, &err);
+ udelay(65);
+ } else {
+ brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+ clkset, clkval);
+ err = -EACCES;
+ goto fail;
+ }
+
+ /* Also, disable the extra SDIO pull-ups */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+ err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs);
+ if (err)
+ goto fail;
+
+ /*
+ * Make sure any on-chip ARM is off (in case strapping is wrong),
+ * or downloaded code was already running.
+ */
+ brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase);
+
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
+ brcmf_sdcard_reg_write(bus->sdiodev,
+ CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
+
+ /* Disable F2 to clear any intermediate frame state on the dongle */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ /* WAR: cmd52 backplane read so core HW will drop ALPReq */
+ clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ 0, NULL);
+
+ /* Done with backplane-dependent accesses, can drop clock... */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ bus->ci = ci;
+ return 0;
+fail:
bus->ci = NULL;
+ kfree(ci);
+ return err;
}
-static void
-brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar)
+static bool
+brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
{
- brcmf_sdbrcm_sdunlock(bus);
- wait_event_interruptible_timeout(bus->ctrl_wait,
- (*lockvar == false), HZ * 2);
- brcmf_sdbrcm_sdlock(bus);
- return;
+ u8 clkctl = 0;
+ int err = 0;
+ int reg_addr;
+ u32 reg_val;
+
+ bus->alp_only = true;
+
+ /* Return the window to backplane enumeration space for core access */
+ if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
+ brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
+
+#ifdef BCMDBG
+ printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n",
+ brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
+
+#endif /* BCMDBG */
+
+ /*
+ * Force PLL off until brcmf_sdbrcm_chip_attach()
+ * programs PLL control regs
+ */
+
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ BRCMF_INIT_CLKCTL1, &err);
+ if (!err)
+ clkctl =
+ brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
+
+ if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
+ brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
+ err, BRCMF_INIT_CLKCTL1, clkctl);
+ goto fail;
+ }
+
+ if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
+ goto fail;
+ }
+
+ if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) {
+ brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip);
+ goto fail;
+ }
+
+ brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH);
+
+ /* Get info on the ARM and SOCRAM cores... */
+ brcmf_sdcard_reg_read(bus->sdiodev,
+ CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
+ bus->ramsize = bus->ci->ramsize;
+ if (!(bus->ramsize)) {
+ brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
+ goto fail;
+ }
+
+ /* Set core control so an SDIO reset does a backplane reset */
+ reg_addr = bus->ci->buscorebase +
+ offsetof(struct sdpcmd_regs, corecontrol);
+ reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
+ brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
+ reg_val | CC_BPRESEN);
+
+ brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
+
+ /* Locate an appropriately-aligned portion of hdrbuf */
+ bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0],
+ BRCMF_SDALIGN);
+
+ /* Set the poll and/or interrupt flags */
+ bus->intr = true;
+ bus->poll = false;
+ if (bus->poll)
+ bus->pollrate = 1;
+
+ return true;
+
+fail:
+ return false;
}
-static void
-brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus)
+static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus)
{
- if (waitqueue_active(&bus->ctrl_wait))
- wake_up_interruptible(&bus->ctrl_wait);
- return;
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* Disable F2 to clear any intermediate frame state on the dongle */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
+
+ bus->drvr->busstate = BRCMF_BUS_DOWN;
+ bus->sleeping = false;
+ bus->rxflow = false;
+
+ /* Done with backplane-dependent accesses, can drop clock... */
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+ SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+ /* ...and initialize clock/power states */
+ bus->clkstate = CLK_SDONLY;
+ bus->idletime = BRCMF_IDLE_INTERVAL;
+ bus->idleclock = BRCMF_IDLE_ACTIVE;
+
+ /* Query the F2 block size, set roundup accordingly */
+ bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
+ bus->roundup = min(max_roundup, bus->blocksize);
+
+ /* bus module does not support packet chaining */
+ bus->use_rxchain = false;
+ bus->sd_rxchain = false;
+
+ return true;
}
static int
@@ -6595,24 +4341,13 @@ brcmf_sdbrcm_watchdog_thread(void *data)
{
struct brcmf_bus *bus = (struct brcmf_bus *)data;
- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
- if (brcmf_watchdog_prio > 0) {
- struct sched_param param;
- param.sched_priority = (brcmf_watchdog_prio < MAX_RT_PRIO) ?
- brcmf_watchdog_prio : (MAX_RT_PRIO - 1);
- sched_setscheduler(current, SCHED_FIFO, &param);
- }
-
allow_signal(SIGTERM);
/* Run until signal received */
while (1) {
if (kthread_should_stop())
break;
if (!wait_for_completion_interruptible(&bus->watchdog_wait)) {
- if (bus->drvr->dongle_reset == false)
- brcmf_sdbrcm_bus_watchdog(bus->drvr);
+ brcmf_sdbrcm_bus_watchdog(bus->drvr);
/* Count the tick for reference */
bus->drvr->tickcnt++;
} else
@@ -6626,147 +4361,237 @@ brcmf_sdbrcm_watchdog(unsigned long data)
{
struct brcmf_bus *bus = (struct brcmf_bus *)data;
- if (brcmf_watchdog_prio >= 0) {
- if (bus->watchdog_tsk)
- complete(&bus->watchdog_wait);
- else
- return;
- } else {
- brcmf_sdbrcm_bus_watchdog(bus->drvr);
-
- /* Count the tick for reference */
- bus->drvr->tickcnt++;
+ if (bus->watchdog_tsk) {
+ complete(&bus->watchdog_wait);
+ /* Reschedule the watchdog */
+ if (bus->wd_timer_valid)
+ mod_timer(&bus->timer,
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
}
-
- /* Reschedule the watchdog */
- if (bus->wd_timer_valid)
- mod_timer(&bus->timer, jiffies + brcmf_watchdog_ms * HZ / 1000);
}
-void
-brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
+static void
+brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
{
- static uint save_ms;
+ brcmf_dbg(TRACE, "Enter\n");
- /* don't start the wd until fw is loaded */
- if (bus->drvr->busstate == BRCMF_BUS_DOWN)
- return;
+ kfree(bus->ci);
+ bus->ci = NULL;
+}
- /* Totally stop the timer */
- if (!wdtick && bus->wd_timer_valid == true) {
- del_timer_sync(&bus->timer);
- bus->wd_timer_valid = false;
- save_ms = wdtick;
- return;
+static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus->ci) {
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+ brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+ brcmf_sdbrcm_chip_detach(bus);
+ if (bus->vars && bus->varsz)
+ kfree(bus->vars);
+ bus->vars = NULL;
}
- if (wdtick) {
- brcmf_watchdog_ms = (uint) wdtick;
+ brcmf_dbg(TRACE, "Disconnected\n");
+}
- if (save_ms != brcmf_watchdog_ms) {
- if (bus->wd_timer_valid == true)
- /* Stop timer and restart at new value */
- del_timer_sync(&bus->timer);
+/* Detach and free everything */
+static void brcmf_sdbrcm_release(struct brcmf_bus *bus)
+{
+ brcmf_dbg(TRACE, "Enter\n");
- /* Create timer again when watchdog period is
- dynamically changed or in the first instance
- */
- bus->timer.expires =
- jiffies + brcmf_watchdog_ms * HZ / 1000;
- add_timer(&bus->timer);
+ if (bus) {
+ /* De-register interrupt handler */
+ brcmf_sdcard_intr_dereg(bus->sdiodev);
- } else {
- /* Re arm the timer, at last watchdog period */
- mod_timer(&bus->timer,
- jiffies + brcmf_watchdog_ms * HZ / 1000);
+ if (bus->drvr) {
+ brcmf_detach(bus->drvr);
+ brcmf_sdbrcm_release_dongle(bus);
+ bus->drvr = NULL;
}
- bus->wd_timer_valid = true;
- save_ms = wdtick;
+ brcmf_sdbrcm_release_malloc(bus);
+
+ kfree(bus);
}
+
+ brcmf_dbg(TRACE, "Disconnected\n");
}
-static int brcmf_sdbrcm_dpc_thread(void *data)
+void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
+ u32 regsva, struct brcmf_sdio_dev *sdiodev)
{
- struct brcmf_bus *bus = (struct brcmf_bus *) data;
+ int ret;
+ struct brcmf_bus *bus;
- /* This thread doesn't need any user-level access,
- * so get rid of all our resources
+ /* Init global variables at run-time, not as part of the declaration.
+ * This is required to support init/de-init of the driver.
+ * Initialization
+ * of globals as part of the declaration results in non-deterministic
+ * behavior since the value of the globals may be different on the
+ * first time that the driver is initialized vs subsequent
+ * initializations.
*/
- if (brcmf_dpc_prio > 0) {
- struct sched_param param;
- param.sched_priority = (brcmf_dpc_prio < MAX_RT_PRIO) ?
- brcmf_dpc_prio : (MAX_RT_PRIO - 1);
- sched_setscheduler(current, SCHED_FIFO, &param);
+ brcmf_c_init();
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ /* We make an assumption about address window mappings:
+ * regsva == SI_ENUM_BASE*/
+
+ /* Allocate private bus interface state */
+ bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC);
+ if (!bus)
+ goto fail;
+
+ bus->sdiodev = sdiodev;
+ sdiodev->bus = bus;
+ bus->txbound = BRCMF_TXBOUND;
+ bus->rxbound = BRCMF_RXBOUND;
+ bus->txminmax = BRCMF_TXMINMAX;
+ bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
+ bus->usebufpool = false; /* Use bufpool if allocated,
+ else use locally malloced rxbuf */
+
+ /* attempt to attach to the dongle */
+ if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
+ goto fail;
}
- allow_signal(SIGTERM);
- /* Run until signal received */
- while (1) {
- if (kthread_should_stop())
- break;
- if (!wait_for_completion_interruptible(&bus->dpc_wait)) {
- /* Call bus dpc unless it indicated down
- (then clean stop) */
- if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
- if (brcmf_sdbrcm_dpc(bus))
- complete(&bus->dpc_wait);
- } else {
- brcmf_sdbrcm_bus_stop(bus, true);
- }
- } else
- break;
+ spin_lock_init(&bus->txqlock);
+ init_waitqueue_head(&bus->ctrl_wait);
+ init_waitqueue_head(&bus->dcmd_resp_wait);
+
+ /* Set up the watchdog timer */
+ init_timer(&bus->timer);
+ bus->timer.data = (unsigned long)bus;
+ bus->timer.function = brcmf_sdbrcm_watchdog;
+
+ /* Initialize thread based operation and lock */
+ sema_init(&bus->sdsem, 1);
+
+ /* Initialize watchdog thread */
+ init_completion(&bus->watchdog_wait);
+ bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
+ bus, "brcmf_watchdog");
+ if (IS_ERR(bus->watchdog_tsk)) {
+ printk(KERN_WARNING
+ "brcmf_watchdog thread failed to start\n");
+ bus->watchdog_tsk = NULL;
+ }
+ /* Initialize DPC thread */
+ init_completion(&bus->dpc_wait);
+ bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread,
+ bus, "brcmf_dpc");
+ if (IS_ERR(bus->dpc_tsk)) {
+ printk(KERN_WARNING
+ "brcmf_dpc thread failed to start\n");
+ bus->dpc_tsk = NULL;
}
- return 0;
-}
-static void brcmf_sdbrcm_dpc_tasklet(unsigned long data)
-{
- struct brcmf_bus *bus = (struct brcmf_bus *) data;
+ /* Attach to the brcmf/OS/network interface */
+ bus->drvr = brcmf_attach(bus, SDPCM_RESERVE);
+ if (!bus->drvr) {
+ brcmf_dbg(ERROR, "brcmf_attach failed\n");
+ goto fail;
+ }
- /* Call bus dpc unless it indicated down (then clean stop) */
- if (bus->drvr->busstate != BRCMF_BUS_DOWN) {
- if (brcmf_sdbrcm_dpc(bus))
- tasklet_schedule(&bus->tasklet);
- } else
- brcmf_sdbrcm_bus_stop(bus, true);
-}
+ /* Allocate buffers */
+ if (!(brcmf_sdbrcm_probe_malloc(bus))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n");
+ goto fail;
+ }
-static void brcmf_sdbrcm_sched_dpc(struct brcmf_bus *bus)
-{
- if (bus->dpc_tsk) {
- complete(&bus->dpc_wait);
- return;
+ if (!(brcmf_sdbrcm_probe_init(bus))) {
+ brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n");
+ goto fail;
}
- tasklet_schedule(&bus->tasklet);
+ /* Register interrupt callback, but mask it (not operational yet). */
+ brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n");
+ ret = brcmf_sdcard_intr_reg(bus->sdiodev);
+ if (ret != 0) {
+ brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret);
+ goto fail;
+ }
+ brcmf_dbg(INTR, "registered SDIO interrupt function ok\n");
+
+ brcmf_dbg(INFO, "completed!!\n");
+
+ /* if firmware path present try to download and bring up bus */
+ ret = brcmf_bus_start(bus->drvr);
+ if (ret != 0) {
+ if (ret == -ENOLINK) {
+ brcmf_dbg(ERROR, "dongle is not responding\n");
+ goto fail;
+ }
+ }
+ /* Ok, have the per-port tell the stack we're open for business */
+ if (brcmf_net_attach(bus->drvr, 0) != 0) {
+ brcmf_dbg(ERROR, "Net attach failed!!\n");
+ goto fail;
+ }
+
+ return bus;
+
+fail:
+ brcmf_sdbrcm_release(bus);
+ return NULL;
}
-static void brcmf_sdbrcm_sdlock(struct brcmf_bus *bus)
+void brcmf_sdbrcm_disconnect(void *ptr)
{
- if (bus->threads_only)
- down(&bus->sdsem);
- else
- spin_lock_bh(&bus->sdlock);
+ struct brcmf_bus *bus = (struct brcmf_bus *)ptr;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ if (bus)
+ brcmf_sdbrcm_release(bus);
+
+ brcmf_dbg(TRACE, "Disconnected\n");
}
-static void brcmf_sdbrcm_sdunlock(struct brcmf_bus *bus)
+struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
{
- if (bus->threads_only)
- up(&bus->sdsem);
- else
- spin_unlock_bh(&bus->sdlock);
+ return &bus->sdiodev->func[2]->dev;
}
-static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus)
+void
+brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
{
- if (bus->firmware->size < bus->fw_ptr + len)
- len = bus->firmware->size - bus->fw_ptr;
+ /* don't start the wd until fw is loaded */
+ if (bus->drvr->busstate == BRCMF_BUS_DOWN)
+ return;
- memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
- bus->fw_ptr += len;
- return len;
-}
+ /* Totally stop the timer */
+ if (!wdtick && bus->wd_timer_valid == true) {
+ del_timer_sync(&bus->timer);
+ bus->wd_timer_valid = false;
+ bus->save_ms = wdtick;
+ return;
+ }
-MODULE_FIRMWARE(BCM4329_FW_NAME);
-MODULE_FIRMWARE(BCM4329_NV_NAME);
+ if (wdtick) {
+ if (bus->save_ms != BRCMF_WD_POLL_MS) {
+ if (bus->wd_timer_valid == true)
+ /* Stop timer and restart at new value */
+ del_timer_sync(&bus->timer);
+
+ /* Create timer again when watchdog period is
+ dynamically changed or in the first instance
+ */
+ bus->timer.expires =
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000;
+ add_timer(&bus->timer);
+
+ } else {
+ /* Re arm the timer, at last watchdog period */
+ mod_timer(&bus->timer,
+ jiffies + BRCMF_WD_POLL_MS * HZ / 1000);
+ }
+
+ bus->wd_timer_valid = true;
+ bus->save_ms = wdtick;
+ }
+}
diff --git a/drivers/staging/brcm80211/brcmfmac/sdio_host.h b/drivers/staging/brcm80211/brcmfmac/sdio_host.h
index d34547215060..726fa8981113 100644
--- a/drivers/staging/brcm80211/brcmfmac/sdio_host.h
+++ b/drivers/staging/brcm80211/brcmfmac/sdio_host.h
@@ -18,7 +18,6 @@
#define _BRCM_SDH_H_
#include <linux/skbuff.h>
-extern const uint brcmf_sdio_msglevel;
#define SDIO_FUNC_0 0
#define SDIO_FUNC_1 1
@@ -41,46 +40,71 @@ extern const uint brcmf_sdio_msglevel;
/* Maximum number of I/O funcs */
#define SDIOD_MAX_IOFUNCS 7
-#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */
+/* as of sdiod rev 0, supports 3 functions */
+#define SBSDIO_NUM_FUNCTION 3
/* function 1 miscellaneous registers */
-#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */
-#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */
-#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */
-#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */
-#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */
-#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */
-#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */
-#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */
-#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */
-#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */
-
-/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */
-#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */
-#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */
-#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */
-#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */
-#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */
-#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */
-#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */
-#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */
-#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */
-#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */
+
+/* sprom command and status */
+#define SBSDIO_SPROM_CS 0x10000
+/* sprom info register */
+#define SBSDIO_SPROM_INFO 0x10001
+/* sprom indirect access data byte 0 */
+#define SBSDIO_SPROM_DATA_LOW 0x10002
+/* sprom indirect access data byte 1 */
+#define SBSDIO_SPROM_DATA_HIGH 0x10003
+/* sprom indirect access addr byte 0 */
+#define SBSDIO_SPROM_ADDR_LOW 0x10004
+/* sprom indirect access addr byte 0 */
+#define SBSDIO_SPROM_ADDR_HIGH 0x10005
+/* xtal_pu (gpio) output */
+#define SBSDIO_CHIP_CTRL_DATA 0x10006
+/* xtal_pu (gpio) enable */
+#define SBSDIO_CHIP_CTRL_EN 0x10007
+/* rev < 7, watermark for sdio device */
+#define SBSDIO_WATERMARK 0x10008
+/* control busy signal generation */
+#define SBSDIO_DEVICE_CTL 0x10009
+
+/* SB Address Window Low (b15) */
+#define SBSDIO_FUNC1_SBADDRLOW 0x1000A
+/* SB Address Window Mid (b23:b16) */
+#define SBSDIO_FUNC1_SBADDRMID 0x1000B
+/* SB Address Window High (b31:b24) */
+#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C
+/* Frame Control (frame term/abort) */
+#define SBSDIO_FUNC1_FRAMECTRL 0x1000D
+/* ChipClockCSR (ALP/HT ctl/status) */
+#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E
+/* SdioPullUp (on cmd, d0-d2) */
+#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F
+/* Write Frame Byte Count Low */
+#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019
+/* Write Frame Byte Count High */
+#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A
+/* Read Frame Byte Count Low */
+#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B
+/* Read Frame Byte Count High */
+#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C
#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */
/* function 1 OCP space */
-#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */
+
+/* sb offset addr is <= 15 bits, 32k */
+#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF
#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
-#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */
+/* with b15, maps to 32-bit SB access */
+#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000
-/* some duplication with sbsdpcmdev.h here */
/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
+
#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */
#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */
#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */
-#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */
+/* Address bits from SBADDR regs */
+#define SBSDIO_SBWINDOW_MASK 0xffff8000
#define SDIOH_READ 0 /* Read request */
#define SDIOH_WRITE 1 /* Write request */
@@ -92,68 +116,32 @@ extern const uint brcmf_sdio_msglevel;
#define SUCCESS 0
#define ERROR 1
-/* forward declarations */
-struct brcmf_sdio_card;
-
struct brcmf_sdreg {
int func;
int offset;
int value;
};
-struct sdioh_info {
- struct osl_info *osh; /* osh handler */
- bool client_intr_enabled; /* interrupt connnected flag */
- bool intr_handler_valid; /* client driver interrupt handler valid */
- void (*intr_handler)(void *); /* registered interrupt handler */
- void *intr_handler_arg; /* argument to call interrupt handler */
- u16 intmask; /* Current active interrupts */
- void *sdos_info; /* Pointer to per-OS private data */
-
- uint irq; /* Client irq */
- int intrcount; /* Client interrupts */
- bool sd_blockmode; /* sd_blockmode == false => 64 Byte Cmd 53s. */
- /* Must be on for sd_multiblock to be effective */
- bool use_client_ints; /* If this is false, make sure to restore */
- int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
- u8 num_funcs; /* Supported funcs on client */
- u32 com_cis_ptr;
+struct brcmf_sdio_dev {
+ struct sdio_func *func[SDIO_MAX_FUNCS];
+ u8 num_funcs; /* Supported funcs on client */
u32 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 */
-};
+ u32 sbwad; /* Save backplane window address */
+ bool regfail; /* status of last reg_r/w call */
+ void *bus;
+ atomic_t suspend; /* suspend flag */
+ wait_queue_head_t request_byte_wait;
+ wait_queue_head_t request_word_wait;
+ wait_queue_head_t request_packet_wait;
+ wait_queue_head_t request_buffer_wait;
-struct brcmf_sdmmc_instance {
- struct sdioh_info *sd;
- struct sdio_func *func[SDIOD_MAX_IOFUNCS];
- u32 host_claimed;
};
-/* Attach and build an interface to the underlying SD host driver.
- * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by
- * brcmf_sdcard.
- * - Returns the sdio card handle and virtual address base for register access.
- * The returned handle should be used in all subsequent calls, but the bcmsh
- * implementation may maintain a single "default" handle (e.g. the first or
- * most recent one) to enable single-instance implementations to pass NULL.
- */
-extern struct brcmf_sdio_card*
-brcmf_sdcard_attach(void *cfghdl, u32 *regsva, uint irq);
-
-/* Detach - freeup resources allocated in attach */
-extern int brcmf_sdcard_detach(struct brcmf_sdio_card *card);
-
-/* Enable/disable SD interrupt */
-extern int brcmf_sdcard_intr_enable(struct brcmf_sdio_card *card);
-extern int brcmf_sdcard_intr_disable(struct brcmf_sdio_card *card);
-
/* Register/deregister device interrupt handler. */
extern int
-brcmf_sdcard_intr_reg(struct brcmf_sdio_card *card,
- void (*fn)(void *), void *argh);
+brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev);
-extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_card *card);
+extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev);
/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
* fn: function number
@@ -161,44 +149,25 @@ extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_card *card);
* data: data byte to write
* err: pointer to error code (or NULL)
*/
-extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_card *card, uint func,
+extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func,
u32 addr, int *err);
-extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_card *card, uint func,
+extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func,
u32 addr, u8 data, int *err);
-/* Read/Write 4bytes from/to cfg space */
-extern u32
-brcmf_sdcard_cfg_read_word(struct brcmf_sdio_card *card, uint fnc_num,
- u32 addr, int *err);
-
-extern void brcmf_sdcard_cfg_write_word(struct brcmf_sdio_card *card,
- uint fnc_num, u32 addr,
- u32 data, int *err);
-
-/* Read CIS content for specified function.
- * fn: function whose CIS is being requested (0 is common CIS)
- * cis: pointer to memory location to place results
- * length: number of bytes to read
- * Internally, this routine uses the values from the cis base regs (0x9-0xB)
- * to form an SDIO-space address to read the data from.
- */
-extern int brcmf_sdcard_cis_read(struct brcmf_sdio_card *card, uint func,
- u8 *cis, uint length);
-
/* Synchronous access to device (client) core registers via CMD53 to F1.
* addr: backplane address (i.e. >= regsva from attach)
* size: register width in bytes (2 or 4)
* data: data for register write
*/
extern u32
-brcmf_sdcard_reg_read(struct brcmf_sdio_card *card, u32 addr, uint size);
+brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size);
extern u32
-brcmf_sdcard_reg_write(struct brcmf_sdio_card *card, u32 addr, uint size,
+brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
u32 data);
/* Indicate if last reg read/write failed */
-extern bool brcmf_sdcard_regfail(struct brcmf_sdio_card *card);
+extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
/* Buffer transfer to/from device (client) core via cmd53.
* fn: function number
@@ -213,25 +182,20 @@ extern bool brcmf_sdcard_regfail(struct brcmf_sdio_card *card);
* NOTE: Async operation is not currently supported.
*/
extern int
-brcmf_sdcard_send_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes, void *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle);
+brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt);
extern int
-brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
- uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt,
- void (*complete)(void *handle, int status,
- bool sync_waiting),
- void *handle);
+brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
+ uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt);
/* Flags bits */
-#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */
-#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */
-#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */
-/* Pending (non-error) return code */
-#define BCME_PENDING 1
+/* Four-byte target (backplane) width (vs. two-byte) */
+#define SDIO_REQ_4BYTE 0x1
+/* Fixed address (FIFO) (vs. incrementing address) */
+#define SDIO_REQ_FIXED 0x2
+/* Async request (vs. sync request) */
+#define SDIO_REQ_ASYNC 0x4
/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only).
* rw: read or write (0/1)
@@ -240,108 +204,49 @@ brcmf_sdcard_recv_buf(struct brcmf_sdio_card *card, u32 addr, uint fn,
* nbytes: number of bytes to transfer to/from buf
* Returns 0 or error code.
*/
-extern int brcmf_sdcard_rwdata(struct brcmf_sdio_card *card, uint rw, u32 addr,
- u8 *buf, uint nbytes);
+extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw,
+ u32 addr, u8 *buf, uint nbytes);
/* Issue an abort to the specified function */
-extern int brcmf_sdcard_abort(struct brcmf_sdio_card *card, uint fn);
-
-/* Returns the "Device ID" of target device on the SDIO bus. */
-extern int brcmf_sdcard_query_device(struct brcmf_sdio_card *card);
-
-/* Miscellaneous knob tweaker. */
-extern int brcmf_sdcard_iovar_op(struct brcmf_sdio_card *card, const char *name,
- void *params, int plen, void *arg, int len,
- bool set);
-
-/* helper functions */
-
-/* callback functions */
-struct brcmf_sdioh_driver {
- /* attach to device */
- void *(*attach) (u16 vend_id, u16 dev_id, u16 bus, u16 slot,
- u16 func, uint bustype, u32 regsva, void *param);
- /* detach from device */
- void (*detach) (void *ch);
-};
-
-struct sdioh_info;
+extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn);
/* platform specific/high level functions */
-extern int brcmf_sdio_function_init(void);
-extern int brcmf_sdio_register(struct brcmf_sdioh_driver *driver);
-extern void brcmf_sdio_unregister(void);
-extern void brcmf_sdio_function_cleanup(void);
-extern int brcmf_sdio_probe(struct device *dev);
-extern int brcmf_sdio_remove(struct device *dev);
+extern int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev);
+extern int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev);
-/* Function to return current window addr */
-extern u32 brcmf_sdcard_cur_sbwad(struct brcmf_sdio_card *card);
-
-/* Allocate/init/free per-OS private data */
-extern int brcmf_sdioh_osinit(struct sdioh_info *sd);
-extern void brcmf_sdioh_osfree(struct sdioh_info *sd);
-
-/* Core interrupt enable/disable of device interrupts */
-extern void brcmf_sdioh_dev_intr_on(struct sdioh_info *sd);
-extern void brcmf_sdioh_dev_intr_off(struct sdioh_info *sd);
+extern int brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev,
+ u32 address);
/* attach, return handler on success, NULL if failed.
* The handler shall be provided by all subsequent calls. No local cache
* cfghdl points to the starting address of pci device mapped memory
*/
-extern struct sdioh_info *brcmf_sdioh_attach(void *cfghdl, uint irq);
-extern int brcmf_sdioh_detach(struct sdioh_info *si);
-
-extern int
-brcmf_sdioh_interrupt_register(struct sdioh_info *si,
- void (*sdioh_cb_fn)(void *), void *argh);
-
-extern int brcmf_sdioh_interrupt_deregister(struct sdioh_info *si);
-
-/* enable or disable SD interrupt */
-extern int
-brcmf_sdioh_interrupt_set(struct sdioh_info *si, bool enable_disable);
+extern int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev);
+extern void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev);
/* read or write one byte using cmd52 */
-extern int
-brcmf_sdioh_request_byte(struct sdioh_info *si, uint rw, uint fnc, uint addr,
- u8 *byte);
+extern int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
+ uint fnc, uint addr, u8 *byte);
/* read or write 2/4 bytes using cmd53 */
extern int
-brcmf_sdioh_request_word(struct sdioh_info *si, uint cmd_type,
+brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev,
uint rw, uint fnc, uint addr,
u32 *word, uint nbyte);
/* read or write any buffer using cmd53 */
extern int
-brcmf_sdioh_request_buffer(struct sdioh_info *si, uint pio_dma,
+brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
uint fix_inc, uint rw, uint fnc_num,
u32 addr, uint regwidth,
u32 buflen, u8 *buffer, struct sk_buff *pkt);
-/* get cis data */
-extern int
-brcmf_sdioh_cis_read(struct sdioh_info *si, uint fuc, u8 *cis, u32 length);
-
-extern int
-brcmf_sdioh_cfg_read(struct sdioh_info *si, uint fuc, u32 addr, u8 *data);
-extern int
-brcmf_sdioh_cfg_write(struct sdioh_info *si, uint fuc, u32 addr, u8 *data);
-
-/* handle iovars */
-extern int brcmf_sdioh_iovar_op(struct sdioh_info *si, const char *name,
- void *params, int plen, void *arg, int len, bool set);
-
-/* Issue abort to the specified function and clear controller as needed */
-extern int brcmf_sdioh_abort(struct sdioh_info *si, uint fnc);
-
/* Watchdog timer interface for pm ops */
-extern void brcmf_sdio_wdtmr_enable(bool enable);
-
-extern uint sd_msglevel; /* Debug message level */
-
-extern struct brcmf_sdmmc_instance *gInstance;
+extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev,
+ bool enable);
+extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
+ u32 regsva, struct brcmf_sdio_dev *sdiodev);
+extern void brcmf_sdbrcm_disconnect(void *ptr);
+extern void brcmf_sdbrcm_isr(void *arg);
#endif /* _BRCM_SDH_H_ */
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
index 821206d3e536..d626ebd05aea 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
@@ -14,19 +14,18 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */
+
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/netdevice.h>
-#include <linux/sched.h>
+#include <linux/bitops.h>
#include <linux/etherdevice.h>
-#include <linux/wireless.h>
#include <linux/ieee80211.h>
-#include <linux/mmc/sdio_func.h>
#include <linux/uaccess.h>
#include <net/cfg80211.h>
-#include <net/rtnetlink.h>
#include <brcmu_utils.h>
#include <defs.h>
@@ -34,306 +33,50 @@
#include "dhd.h"
#include "wl_cfg80211.h"
-static struct sdio_func *cfg80211_sdio_func;
-static struct brcmf_cfg80211_dev *cfg80211_dev;
-static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
-
-u32 brcmf_dbg_level = WL_DBG_ERR;
+#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \
+ (sizeof(struct brcmf_assoc_params_le) - sizeof(u16))
-/*
-** cfg80211_ops api/callback list
-*/
-static s32 brcmf_cfg80211_change_iface(struct wiphy *wiphy,
- struct net_device *ndev,
- enum nl80211_iftype type, u32 *flags,
- struct vif_params *params);
-static s32 __brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_scan_request *request,
- struct cfg80211_ssid *this_ssid);
-static s32 brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
- struct cfg80211_scan_request *request);
-static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
-static s32 brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_ibss_params *params);
-static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy,
- struct net_device *dev);
-static s32 brcmf_cfg80211_get_station(struct wiphy *wiphy,
- struct net_device *dev, u8 *mac,
- struct station_info *sinfo);
-static s32 brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy,
- struct net_device *dev, bool enabled,
- s32 timeout);
-static s32 brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy,
- struct net_device *dev,
- const u8 *addr,
- const struct cfg80211_bitrate_mask
- *mask);
-static int brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_connect_params *sme);
-static s32 brcmf_cfg80211_disconnect(struct wiphy *wiphy,
- struct net_device *dev,
- u16 reason_code);
-static s32 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
- enum nl80211_tx_power_setting type,
- s32 dbm);
-static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
-static s32 brcmf_cfg80211_config_default_key(struct wiphy *wiphy,
- struct net_device *dev, u8 key_idx,
- bool unicast, bool multicast);
-static s32 brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, bool pairwise, const u8 *mac_addr,
- struct key_params *params);
-static s32 brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, bool pairwise, const u8 *mac_addr);
-static s32 brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, bool pairwise, const u8 *mac_addr,
- void *cookie, void (*callback) (void *cookie,
- struct
- key_params *
- params));
-static s32 brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
- struct net_device *dev,
- u8 key_idx);
-static s32 brcmf_cfg80211_resume(struct wiphy *wiphy);
-static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
- struct cfg80211_wowlan *wow);
-static s32 brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_pmksa *pmksa);
-static s32 brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
- struct cfg80211_pmksa *pmksa);
-static s32 brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy,
- struct net_device *dev);
-/*
-** event & event Q handlers for cfg80211 interfaces
-*/
-static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_event_handler(void *data);
-static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el);
-static struct brcmf_cfg80211_event_q *
-brcmf_deq_event(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 type,
- const struct brcmf_event_msg *msg, void *data);
-static void brcmf_put_event(struct brcmf_cfg80211_event_q *e);
-static void brcmf_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e,
- void *data);
-static s32 brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e,
- void *data);
-static s32 brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e,
- void *data);
-static s32 brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data,
- bool completed);
-static s32 brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data);
-static s32 brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data);
-
-/*
-** register/deregister sdio function
-*/
-static void brcmf_clear_sdio_func(void);
-
-/*
-** ioctl utilites
-*/
-static s32 brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
- s32 buf_len);
-static __used s32 brcmf_dev_bufvar_set(struct net_device *dev, s8 *name,
- s8 *buf, s32 len);
-static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
-static s32 brcmf_dev_intvar_get(struct net_device *dev, s8 *name,
- s32 *retval);
-static s32 brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg,
- u32 len);
-
-/*
-** cfg80211 set_wiphy_params utilities
-*/
-static s32 brcmf_set_frag(struct net_device *dev, u32 frag_threshold);
-static s32 brcmf_set_rts(struct net_device *dev, u32 frag_threshold);
-static s32 brcmf_set_retry(struct net_device *dev, u32 retry, bool l);
-
-/*
-** wl profile utilities
-*/
-static s32 brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
- const struct brcmf_event_msg *e,
- void *data, s32 item);
-static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item);
-static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof);
-
-/*
-** cfg80211 connect utilites
-*/
-static s32 brcmf_set_wpa_version(struct net_device *dev,
- struct cfg80211_connect_params *sme);
-static s32 brcmf_set_auth_type(struct net_device *dev,
- struct cfg80211_connect_params *sme);
-static s32 brcmf_set_set_cipher(struct net_device *dev,
- struct cfg80211_connect_params *sme);
-static s32 brcmf_set_key_mgmt(struct net_device *dev,
- struct cfg80211_connect_params *sme);
-static s32 brcmf_set_set_sharedkey(struct net_device *dev,
- struct cfg80211_connect_params *sme);
-static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_ch_to_chanspec(int ch,
- struct brcmf_join_params *join_params, size_t *join_params_size);
-
-/*
-** information element utilities
-*/
-static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
- u8 t, u8 l, u8 *v);
-static s32 brcmf_mode_to_nl80211_iftype(s32 mode);
-static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
- struct device *dev);
-static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
- struct brcmf_bss_info *bi);
-static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, const u8 *mac_addr,
- struct key_params *params);
-
-/*
-** key indianess swap utilities
-*/
-static void swap_key_from_BE(struct brcmf_wsec_key *key);
-static void swap_key_to_BE(struct brcmf_wsec_key *key);
-
-/*
-** brcmf_cfg80211_priv memory init/deinit utilities
-*/
-static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv);
-
-static void brcmf_delay(u32 ms);
+static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
-/*
-** store/restore cfg80211 instance data
-*/
-static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data);
-static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev);
+static u32 brcmf_dbg_level = WL_DBG_ERR;
-/*
-** ibss mode utilities
-*/
static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv);
+static s32
+brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev, const struct brcmf_event_msg *e,
+ bool completed);
-/*
-** dongle up/down , default configuration utilities
-*/
-static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv,
- const struct brcmf_event_msg *e);
-static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv,
- const struct brcmf_event_msg *e);
-static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv,
- const struct brcmf_event_msg *e);
-static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype);
-static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf);
-
-/*
-** dongle configuration utilities
-*/
-static s32 brcmf_dongle_eventmsg(struct net_device *ndev);
-static s32 brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time, s32 scan_passive_time);
-static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv,
- bool need_lock);
-static s32 brcmf_dongle_roam(struct net_device *ndev, u32 roamvar,
- u32 bcn_timeout);
-
-/*
-** iscan handler
-*/
-static void brcmf_iscan_timer(unsigned long data);
-static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_iscan_thread(void *data);
-static s32 brcmf_dev_iovar_setbuf(struct net_device *dev, s8 *iovar,
- void *param, s32 paramlen, void *bufptr,
- s32 buflen);
-static s32 brcmf_dev_iovar_getbuf(struct net_device *dev, s8 *iovar,
- void *param, s32 paramlen, void *bufptr,
- s32 buflen);
-static s32 brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
- struct brcmf_ssid *ssid, u16 action);
-static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan);
-static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan,
- u32 *status,
- struct brcmf_scan_results **bss_list);
-static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
- bool aborted);
-static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el);
-static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv);
-static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv);
+static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data)
+{
+ dev->driver_data = data;
+}
-/*
-* find most significant bit set
-*/
-static __used u32 brcmf_find_msb(u16 bit16);
+static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev)
+{
+ void *data = NULL;
-/*
-* update pmklist to dongle
-*/
-static __used s32 brcmf_update_pmklist(struct net_device *dev,
- struct brcmf_cfg80211_pmk_list *pmk_list,
- s32 err);
+ if (dev)
+ data = dev->driver_data;
+ return data;
+}
-static void brcmf_set_mpc(struct net_device *ndev, int mpc);
+static
+struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev)
+{
+ struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev);
+ return ci->cfg_priv;
+}
-/*
-* debufs support
-*/
-static int
-brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv);
-static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv);
-
-#define WL_PRIV_GET() \
- ({ \
- struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg80211_dev); \
- if (unlikely(!ci)) { \
- WL_ERR("wl_cfg80211_dev is unavailable\n"); \
- BUG(); \
- } \
- ci->cfg_priv; \
-})
-
-#define CHECK_SYS_UP() \
-do { \
- struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); \
- if (unlikely(!test_bit(WL_STATUS_READY, &cfg_priv->status))) { \
- WL_INFO("device is not ready : status (%d)\n", \
- (int)cfg_priv->status); \
- return -EIO; \
- } \
-} while (0)
+static bool check_sys_up(struct wiphy *wiphy)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
+ if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ WL_INFO("device is not ready : status (%d)\n",
+ (int)cfg_priv->status);
+ return false;
+ }
+ return true;
+}
#define CHAN2G(_channel, _freq, _flags) { \
.band = IEEE80211_BAND_2GHZ, \
@@ -510,48 +253,134 @@ static const u32 __wl_cipher_suites[] = {
WLAN_CIPHER_SUITE_AES_CMAC,
};
-static void swap_key_from_BE(struct brcmf_wsec_key *key)
+/* tag_ID/length/value_buffer tuple */
+struct brcmf_tlv {
+ u8 id;
+ u8 len;
+ u8 data[1];
+};
+
+/* Quarter dBm units to mW
+ * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
+ * Table is offset so the last entry is largest mW value that fits in
+ * a u16.
+ */
+
+#define QDBM_OFFSET 153 /* Offset for first entry */
+#define QDBM_TABLE_LEN 40 /* Table size */
+
+/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
+ * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
+ */
+#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
+
+/* Largest mW value that will round down to the last table entry,
+ * QDBM_OFFSET + QDBM_TABLE_LEN-1.
+ * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
+ * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
+ */
+#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
+
+static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
+/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
+/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
+/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
+/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
+/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
+/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
+};
+
+static u16 brcmf_qdbm_to_mw(u8 qdbm)
{
- key->index = cpu_to_le32(key->index);
- key->len = cpu_to_le32(key->len);
- key->algo = cpu_to_le32(key->algo);
- key->flags = cpu_to_le32(key->flags);
- key->rxiv.hi = cpu_to_le32(key->rxiv.hi);
- key->rxiv.lo = cpu_to_le16(key->rxiv.lo);
- key->iv_initialized = cpu_to_le32(key->iv_initialized);
+ uint factor = 1;
+ int idx = qdbm - QDBM_OFFSET;
+
+ if (idx >= QDBM_TABLE_LEN)
+ /* clamp to max u16 mW value */
+ return 0xFFFF;
+
+ /* scale the qdBm index up to the range of the table 0-40
+ * where an offset of 40 qdBm equals a factor of 10 mW.
+ */
+ while (idx < 0) {
+ idx += 40;
+ factor *= 10;
+ }
+
+ /* return the mW value scaled down to the correct factor of 10,
+ * adding in factor/2 to get proper rounding.
+ */
+ return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
}
-static void swap_key_to_BE(struct brcmf_wsec_key *key)
+static u8 brcmf_mw_to_qdbm(u16 mw)
{
- key->index = le32_to_cpu(key->index);
- key->len = le32_to_cpu(key->len);
- key->algo = le32_to_cpu(key->algo);
- key->flags = le32_to_cpu(key->flags);
- key->rxiv.hi = le32_to_cpu(key->rxiv.hi);
- key->rxiv.lo = le16_to_cpu(key->rxiv.lo);
- key->iv_initialized = le32_to_cpu(key->iv_initialized);
+ u8 qdbm;
+ int offset;
+ uint mw_uint = mw;
+ uint boundary;
+
+ /* handle boundary case */
+ if (mw_uint <= 1)
+ return 0;
+
+ offset = QDBM_OFFSET;
+
+ /* move mw into the range of the table */
+ while (mw_uint < QDBM_TABLE_LOW_BOUND) {
+ mw_uint *= 10;
+ offset -= 40;
+ }
+
+ for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
+ boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
+ nqdBm_to_mW_map[qdbm]) / 2;
+ if (mw_uint < boundary)
+ break;
+ }
+
+ qdbm += (u8) offset;
+
+ return qdbm;
}
-static s32
-brcmf_dev_ioctl(struct net_device *dev, u32 cmd, void *arg, u32 len)
+/* function for reading/writing a single u32 from/to the dongle */
+static int
+brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par)
{
- struct ifreq ifr;
- struct brcmf_ioctl ioc;
- mm_segment_t fs;
- s32 err = 0;
+ int err;
+ __le32 par_le = cpu_to_le32(*par);
+
+ err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32));
+ *par = le32_to_cpu(par_le);
+
+ return err;
+}
- memset(&ioc, 0, sizeof(ioc));
- ioc.cmd = cmd;
- ioc.buf = arg;
- ioc.len = len;
- strcpy(ifr.ifr_name, dev->name);
- ifr.ifr_data = (caddr_t)&ioc;
+static void convert_key_from_CPU(struct brcmf_wsec_key *key,
+ struct brcmf_wsec_key_le *key_le)
+{
+ key_le->index = cpu_to_le32(key->index);
+ key_le->len = cpu_to_le32(key->len);
+ key_le->algo = cpu_to_le32(key->algo);
+ key_le->flags = cpu_to_le32(key->flags);
+ key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi);
+ key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo);
+ key_le->iv_initialized = cpu_to_le32(key->iv_initialized);
+ memcpy(key_le->data, key->data, sizeof(key->data));
+ memcpy(key_le->ea, key->ea, sizeof(key->ea));
+}
- fs = get_fs();
- set_fs(get_ds());
- err = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
- set_fs(fs);
+static int send_key_to_dongle(struct net_device *ndev,
+ struct brcmf_wsec_key *key)
+{
+ int err;
+ struct brcmf_wsec_key_le key_le;
+ convert_key_from_CPU(key, &key_le);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le));
+ if (err)
+ WL_ERR("WLC_SET_KEY error (%d)\n", err);
return err;
}
@@ -566,7 +395,8 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
switch (type) {
case NL80211_IFTYPE_MONITOR:
@@ -587,9 +417,8 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
- infra = cpu_to_le32(infra);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_INFRA, &infra, sizeof(infra));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
+ if (err) {
WL_ERR("WLC_SET_INFRA error (%d)\n", err);
err = -EAGAIN;
} else {
@@ -606,83 +435,134 @@ done:
return err;
}
-static void wl_iscan_prep(struct brcmf_scan_params *params,
+static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val)
+{
+ s8 buf[BRCMF_DCMD_SMLEN];
+ u32 len;
+ s32 err = 0;
+ __le32 val_le;
+
+ val_le = cpu_to_le32(val);
+ len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf,
+ sizeof(buf));
+ BUG_ON(!len);
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len);
+ if (err)
+ WL_ERR("error (%d)\n", err);
+
+ return err;
+}
+
+static s32
+brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval)
+{
+ union {
+ s8 buf[BRCMF_DCMD_SMLEN];
+ __le32 val;
+ } var;
+ u32 len;
+ u32 data_null;
+ s32 err = 0;
+
+ len =
+ brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
+ sizeof(var.buf));
+ BUG_ON(!len);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len);
+ if (err)
+ WL_ERR("error (%d)\n", err);
+
+ *retval = le32_to_cpu(var.val);
+
+ return err;
+}
+
+static void brcmf_set_mpc(struct net_device *ndev, int mpc)
+{
+ s32 err = 0;
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+
+ if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+ err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
+ if (err) {
+ WL_ERR("fail to set mpc\n");
+ return;
+ }
+ WL_INFO("MPC : %d\n", mpc);
+ }
+}
+
+static void wl_iscan_prep(struct brcmf_scan_params_le *params_le,
struct brcmf_ssid *ssid)
{
- memcpy(params->bssid, ether_bcast, ETH_ALEN);
- params->bss_type = DOT11_BSSTYPE_ANY;
- params->scan_type = 0;
- params->nprobes = -1;
- params->active_time = -1;
- params->passive_time = -1;
- params->home_time = -1;
- params->channel_num = 0;
-
- params->nprobes = cpu_to_le32(params->nprobes);
- params->active_time = cpu_to_le32(params->active_time);
- params->passive_time = cpu_to_le32(params->passive_time);
- params->home_time = cpu_to_le32(params->home_time);
+ memcpy(params_le->bssid, ether_bcast, ETH_ALEN);
+ params_le->bss_type = DOT11_BSSTYPE_ANY;
+ params_le->scan_type = 0;
+ params_le->channel_num = 0;
+ params_le->nprobes = cpu_to_le32(-1);
+ params_le->active_time = cpu_to_le32(-1);
+ params_le->passive_time = cpu_to_le32(-1);
+ params_le->home_time = cpu_to_le32(-1);
if (ssid && ssid->SSID_len)
- memcpy(&params->ssid, ssid, sizeof(struct brcmf_ssid));
-
+ memcpy(&params_le->ssid_le, ssid, sizeof(struct brcmf_ssid));
}
static s32
-brcmf_dev_iovar_setbuf(struct net_device *dev, s8 * iovar, void *param,
+brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param,
s32 paramlen, void *bufptr, s32 buflen)
{
s32 iolen;
- iolen = brcmu_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
BUG_ON(!iolen);
- return brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, bufptr, iolen);
+ return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen);
}
static s32
-brcmf_dev_iovar_getbuf(struct net_device *dev, s8 * iovar, void *param,
+brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param,
s32 paramlen, void *bufptr, s32 buflen)
{
s32 iolen;
- iolen = brcmu_mkiovar(iovar, param, paramlen, bufptr, buflen);
+ iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen);
BUG_ON(!iolen);
- return brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, bufptr, buflen);
+ return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen);
}
static s32
brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
struct brcmf_ssid *ssid, u16 action)
{
- s32 params_size = (BRCMF_SCAN_PARAMS_FIXED_SIZE +
- offsetof(struct brcmf_iscan_params, params));
- struct brcmf_iscan_params *params;
+ s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
+ offsetof(struct brcmf_iscan_params_le, params_le);
+ struct brcmf_iscan_params_le *params;
s32 err = 0;
if (ssid && ssid->SSID_len)
params_size += sizeof(struct brcmf_ssid);
params = kzalloc(params_size, GFP_KERNEL);
- if (unlikely(!params))
+ if (!params)
return -ENOMEM;
- BUG_ON(params_size >= BRCMF_C_IOCTL_SMLEN);
+ BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
- wl_iscan_prep(&params->params, ssid);
+ wl_iscan_prep(&params->params_le, ssid);
params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
params->action = cpu_to_le16(action);
params->scan_duration = cpu_to_le16(0);
- /* params_size += offsetof(struct brcmf_iscan_params, params); */
- err = brcmf_dev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
- iscan->ioctl_buf, BRCMF_C_IOCTL_SMLEN);
- if (unlikely(err)) {
- if (err == -EBUSY) {
+ err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size,
+ iscan->dcmd_buf, BRCMF_DCMD_SMLEN);
+ if (err) {
+ if (err == -EBUSY)
WL_INFO("system busy : iscan canceled\n");
- } else {
+ else
WL_ERR("error (%d)\n", err);
- }
}
+
kfree(params);
return err;
}
@@ -692,7 +572,7 @@ static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv)
struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
struct net_device *ndev = cfg_to_ndev(cfg_priv);
struct brcmf_ssid ssid;
- s32 passive_scan;
+ __le32 passive_scan;
s32 err = 0;
/* Broadcast scan by default */
@@ -700,19 +580,23 @@ static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv)
iscan->state = WL_ISCAN_STATE_SCANING;
- passive_scan = cfg_priv->active_scan ? 0 : 1;
- err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN,
+ passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
+ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN,
&passive_scan, sizeof(passive_scan));
- if (unlikely(err)) {
+ if (err) {
WL_ERR("error (%d)\n", err);
return err;
}
brcmf_set_mpc(ndev, 0);
cfg_priv->iscan_kickstart = true;
- brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
+ err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
+ if (err) {
+ brcmf_set_mpc(ndev, 1);
+ cfg_priv->iscan_kickstart = false;
+ return err;
+ }
mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
iscan->timer_on = 1;
-
return err;
}
@@ -724,16 +608,17 @@ __brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
struct cfg80211_ssid *ssids;
struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int;
- s32 passive_scan;
+ __le32 passive_scan;
bool iscan_req;
bool spec_scan;
s32 err = 0;
+ u32 SSID_len;
- if (unlikely(test_bit(WL_STATUS_SCANNING, &cfg_priv->status))) {
+ if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status);
return -EAGAIN;
}
- if (unlikely(test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status))) {
+ if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) {
WL_ERR("Scanning being aborted : status (%lu)\n",
cfg_priv->status);
return -EAGAIN;
@@ -761,41 +646,41 @@ __brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
set_bit(WL_STATUS_SCANNING, &cfg_priv->status);
if (iscan_req) {
err = brcmf_do_iscan(cfg_priv);
- if (likely(!err))
+ if (!err)
return err;
else
goto scan_out;
} else {
WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
ssids->ssid, ssids->ssid_len);
- memset(&sr->ssid, 0, sizeof(sr->ssid));
- sr->ssid.SSID_len =
- min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
- if (sr->ssid.SSID_len) {
- memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
- sr->ssid.SSID_len = cpu_to_le32(sr->ssid.SSID_len);
+ memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
+ SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
+ sr->ssid_le.SSID_len = cpu_to_le32(0);
+ if (SSID_len) {
+ memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
+ sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
spec_scan = true;
} else {
WL_SCAN("Broadcast scan\n");
}
- passive_scan = cfg_priv->active_scan ? 0 : 1;
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_PASSIVE_SCAN,
+ passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN,
&passive_scan, sizeof(passive_scan));
- if (unlikely(err)) {
+ if (err) {
WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
goto scan_out;
}
brcmf_set_mpc(ndev, 0);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SCAN, &sr->ssid,
- sizeof(sr->ssid));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le,
+ sizeof(sr->ssid_le));
if (err) {
- if (err == -EBUSY) {
- WL_INFO("system busy : scan for \"%s\" canceled\n",
- sr->ssid.SSID);
- } else {
+ if (err == -EBUSY)
+ WL_INFO("system busy : scan for \"%s\" "
+ "canceled\n", sr->ssid_le.SSID);
+ else
WL_ERR("WLC_SCAN error (%d)\n", err);
- }
+
brcmf_set_mpc(ndev, 1);
goto scan_out;
}
@@ -817,88 +702,46 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL);
- if (unlikely(err))
+ if (err)
WL_ERR("scan error (%d)\n", err);
WL_TRACE("Exit\n");
return err;
}
-static s32 brcmf_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
+static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold)
{
- s8 buf[BRCMF_C_IOCTL_SMLEN];
- u32 len;
s32 err = 0;
- val = cpu_to_le32(val);
- len = brcmu_mkiovar(name, (char *)(&val), sizeof(val), buf,
- sizeof(buf));
- BUG_ON(!len);
-
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, buf, len);
- if (unlikely(err))
- WL_ERR("error (%d)\n", err);
-
- return err;
-}
-
-static s32
-brcmf_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
-{
- union {
- s8 buf[BRCMF_C_IOCTL_SMLEN];
- s32 val;
- } var;
- u32 len;
- u32 data_null;
- s32 err = 0;
-
- len =
- brcmu_mkiovar(name, (char *)(&data_null), 0, (char *)(&var),
- sizeof(var.buf));
- BUG_ON(!len);
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, &var, len);
- if (unlikely(err))
- WL_ERR("error (%d)\n", err);
-
- *retval = le32_to_cpu(var.val);
-
- return err;
-}
-
-static s32 brcmf_set_rts(struct net_device *dev, u32 rts_threshold)
-{
- s32 err = 0;
-
- err = brcmf_dev_intvar_set(dev, "rtsthresh", rts_threshold);
- if (unlikely(err))
+ err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold);
+ if (err)
WL_ERR("Error (%d)\n", err);
return err;
}
-static s32 brcmf_set_frag(struct net_device *dev, u32 frag_threshold)
+static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
{
s32 err = 0;
- err = brcmf_dev_intvar_set(dev, "fragthresh", frag_threshold);
- if (unlikely(err))
+ err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold);
+ if (err)
WL_ERR("Error (%d)\n", err);
return err;
}
-static s32 brcmf_set_retry(struct net_device *dev, u32 retry, bool l)
+static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
{
s32 err = 0;
u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
- retry = cpu_to_le32(retry);
- err = brcmf_dev_ioctl(dev, cmd, &retry, sizeof(retry));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, cmd, &retry);
+ if (err) {
WL_ERR("cmd (%d) , error (%d)\n", cmd, err);
return err;
}
@@ -912,7 +755,8 @@ static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
(cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) {
@@ -948,8 +792,125 @@ done:
return err;
}
+static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item)
+{
+ switch (item) {
+ case WL_PROF_SEC:
+ return &cfg_priv->profile->sec;
+ case WL_PROF_BSSID:
+ return &cfg_priv->profile->bssid;
+ case WL_PROF_SSID:
+ return &cfg_priv->profile->ssid;
+ }
+ WL_ERR("invalid item (%d)\n", item);
+ return NULL;
+}
+
+static s32
+brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
+ const struct brcmf_event_msg *e, void *data, s32 item)
+{
+ s32 err = 0;
+ struct brcmf_ssid *ssid;
+
+ switch (item) {
+ case WL_PROF_SSID:
+ ssid = (struct brcmf_ssid *) data;
+ memset(cfg_priv->profile->ssid.SSID, 0,
+ sizeof(cfg_priv->profile->ssid.SSID));
+ memcpy(cfg_priv->profile->ssid.SSID,
+ ssid->SSID, ssid->SSID_len);
+ cfg_priv->profile->ssid.SSID_len = ssid->SSID_len;
+ break;
+ case WL_PROF_BSSID:
+ if (data)
+ memcpy(cfg_priv->profile->bssid, data, ETH_ALEN);
+ else
+ memset(cfg_priv->profile->bssid, 0, ETH_ALEN);
+ break;
+ case WL_PROF_SEC:
+ memcpy(&cfg_priv->profile->sec, data,
+ sizeof(cfg_priv->profile->sec));
+ break;
+ case WL_PROF_BEACONINT:
+ cfg_priv->profile->beacon_interval = *(u16 *)data;
+ break;
+ case WL_PROF_DTIMPERIOD:
+ cfg_priv->profile->dtim_period = *(u8 *)data;
+ break;
+ default:
+ WL_ERR("unsupported item (%d)\n", item);
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
+{
+ memset(prof, 0, sizeof(*prof));
+}
+
+static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
+ size_t *join_params_size)
+{
+ u16 chanspec = 0;
+
+ if (ch != 0) {
+ if (ch <= CH_MAX_2G_CHANNEL)
+ chanspec |= WL_CHANSPEC_BAND_2G;
+ else
+ chanspec |= WL_CHANSPEC_BAND_5G;
+
+ chanspec |= WL_CHANSPEC_BW_20;
+ chanspec |= WL_CHANSPEC_CTL_SB_NONE;
+
+ *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
+ sizeof(u16);
+
+ chanspec |= (ch & WL_CHANSPEC_CHAN_MASK);
+ join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec);
+ join_params->params_le.chanspec_num = cpu_to_le32(1);
+
+ WL_CONN("join_params->params.chanspec_list[0]= %#X,"
+ "channel %d, chanspec %#X\n",
+ chanspec, ch, chanspec);
+ }
+}
+
+static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+
+ if (test_and_clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
+ if (!brcmf_is_ibssmode(cfg_priv)) {
+ WL_CONN("Calling cfg80211_disconnected\n ");
+ cfg80211_disconnected(ndev, 0, NULL, 0,
+ GFP_KERNEL);
+ }
+ if (cfg_priv->link_up) {
+ WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0);
+ if (unlikely(err))
+ WL_ERR("WLC_DISASSOC failed (%d)\n", err);
+ cfg_priv->link_up = false;
+ }
+ }
+
+ if (brcmf_is_ibssmode(cfg_priv))
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ else
+ brcmf_bss_connect_done(cfg_priv, ndev, NULL, false);
+
+ WL_TRACE("Exit\n");
+}
+
static s32
-brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_ibss_params *params)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
@@ -958,9 +919,11 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
s32 err = 0;
s32 wsec = 0;
s32 bcnprd;
+ struct brcmf_ssid ssid;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
if (params->ssid)
WL_CONN("SSID: %s\n", params->ssid);
@@ -1012,20 +975,20 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
if (params->privacy)
wsec |= WEP_ENABLED;
- err = brcmf_dev_intvar_set(dev, "wsec", wsec);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+ if (err) {
WL_ERR("wsec failed (%d)\n", err);
goto done;
}
/* Configure Beacon Interval for starter */
if (params->beacon_interval)
- bcnprd = cpu_to_le32(params->beacon_interval);
+ bcnprd = params->beacon_interval;
else
- bcnprd = cpu_to_le32(100);
+ bcnprd = 100;
- err = brcmf_dev_ioctl(dev, BRCM_SET_BCNPRD, &bcnprd, sizeof(bcnprd));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd);
+ if (err) {
WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
goto done;
}
@@ -1034,23 +997,24 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
memset(&join_params, 0, sizeof(struct brcmf_join_params));
/* SSID */
- join_params.ssid.SSID_len =
- (params->ssid_len > 32) ? 32 : params->ssid_len;
- memcpy(join_params.ssid.SSID, params->ssid, join_params.ssid.SSID_len);
- join_params.ssid.SSID_len = cpu_to_le32(join_params.ssid.SSID_len);
- join_params_size = sizeof(join_params.ssid);
- brcmf_update_prof(cfg_priv, NULL, &join_params.ssid, WL_PROF_SSID);
+ ssid.SSID_len = min_t(u32, params->ssid_len, 32);
+ memcpy(ssid.SSID, params->ssid, ssid.SSID_len);
+ memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len);
+ join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
+ join_params_size = sizeof(join_params.ssid_le);
+ brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
/* BSSID */
if (params->bssid) {
- memcpy(join_params.params.bssid, params->bssid, ETH_ALEN);
- join_params_size = sizeof(join_params.ssid) +
- BRCMF_ASSOC_PARAMS_FIXED_SIZE;
+ memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN);
+ join_params_size = sizeof(join_params.ssid_le) +
+ BRCMF_ASSOC_PARAMS_FIXED_SIZE;
} else {
- memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
+ memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
}
+
brcmf_update_prof(cfg_priv, NULL,
- &join_params.params.bssid, WL_PROF_BSSID);
+ &join_params.params_le.bssid, WL_PROF_BSSID);
/* Channel */
if (params->channel) {
@@ -1066,10 +1030,10 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
}
/* set channel for starter */
- target_channel = cpu_to_le32(cfg_priv->channel);
- err = brcmf_dev_ioctl(dev, BRCM_SET_CHANNEL,
- &target_channel, sizeof(target_channel));
- if (unlikely(err)) {
+ target_channel = cfg_priv->channel;
+ err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL,
+ &target_channel);
+ if (err) {
WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
goto done;
}
@@ -1079,9 +1043,9 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
cfg_priv->ibss_starter = false;
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_SSID,
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
&join_params, join_params_size);
- if (unlikely(err)) {
+ if (err) {
WL_ERR("WLC_SET_SSID failed (%d)\n", err);
goto done;
}
@@ -1093,13 +1057,15 @@ done:
return err;
}
-static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+static s32
+brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
brcmf_link_down(cfg_priv);
@@ -1108,10 +1074,10 @@ static s32 brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev
return err;
}
-static s32
-brcmf_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
+static s32 brcmf_set_wpa_version(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
struct brcmf_cfg80211_security *sec;
s32 val = 0;
s32 err = 0;
@@ -1123,8 +1089,8 @@ brcmf_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sm
else
val = WPA_AUTH_DISABLED;
WL_CONN("setting wpa_auth to 0x%0x\n", val);
- err = brcmf_dev_intvar_set(dev, "wpa_auth", val);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
+ if (err) {
WL_ERR("set wpa_auth failed (%d)\n", err);
return err;
}
@@ -1133,10 +1099,10 @@ brcmf_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sm
return err;
}
-static s32
-brcmf_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
+static s32 brcmf_set_auth_type(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
struct brcmf_cfg80211_security *sec;
s32 val = 0;
s32 err = 0;
@@ -1162,8 +1128,8 @@ brcmf_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
break;
}
- err = brcmf_dev_intvar_set(dev, "auth", val);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "auth", val);
+ if (err) {
WL_ERR("set auth failed (%d)\n", err);
return err;
}
@@ -1173,9 +1139,10 @@ brcmf_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
}
static s32
-brcmf_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
+brcmf_set_set_cipher(struct net_device *ndev,
+ struct cfg80211_connect_params *sme)
{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
struct brcmf_cfg80211_security *sec;
s32 pval = 0;
s32 gval = 0;
@@ -1225,8 +1192,8 @@ brcmf_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme
}
WL_CONN("pval (%d) gval (%d)\n", pval, gval);
- err = brcmf_dev_intvar_set(dev, "wsec", pval | gval);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval);
+ if (err) {
WL_ERR("error (%d)\n", err);
return err;
}
@@ -1239,16 +1206,16 @@ brcmf_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme
}
static s32
-brcmf_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
+brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
struct brcmf_cfg80211_security *sec;
s32 val = 0;
s32 err = 0;
if (sme->crypto.n_akm_suites) {
- err = brcmf_dev_intvar_get(dev, "wpa_auth", &val);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val);
+ if (err) {
WL_ERR("could not get wpa_auth (%d)\n", err);
return err;
}
@@ -1281,8 +1248,8 @@ brcmf_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
}
WL_CONN("setting wpa_auth to %d\n", val);
- err = brcmf_dev_intvar_set(dev, "wpa_auth", val);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "wpa_auth", val);
+ if (err) {
WL_ERR("could not set wpa_auth (%d)\n", err);
return err;
}
@@ -1294,86 +1261,88 @@ brcmf_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
}
static s32
-brcmf_set_set_sharedkey(struct net_device *dev,
+brcmf_set_wep_sharedkey(struct net_device *ndev,
struct cfg80211_connect_params *sme)
{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
struct brcmf_cfg80211_security *sec;
struct brcmf_wsec_key key;
s32 val;
s32 err = 0;
WL_CONN("key len (%d)\n", sme->key_len);
- if (sme->key_len) {
- sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
- WL_CONN("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))) {
- memset(&key, 0, sizeof(key));
- key.len = (u32) sme->key_len;
- key.index = (u32) sme->key_idx;
- if (unlikely(key.len > sizeof(key.data))) {
- WL_ERR("Too long key length (%u)\n", key.len);
- return -EINVAL;
- }
- memcpy(key.data, sme->key, key.len);
- key.flags = BRCMF_PRIMARY_KEY;
- switch (sec->cipher_pairwise) {
- case WLAN_CIPHER_SUITE_WEP40:
- key.algo = CRYPTO_ALGO_WEP1;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- key.algo = CRYPTO_ALGO_WEP128;
- break;
- default:
- WL_ERR("Invalid algorithm (%d)\n",
- sme->crypto.ciphers_pairwise[0]);
- return -EINVAL;
- }
- /* Set the new key/index */
- WL_CONN("key length (%d) key index (%d) algo (%d)\n",
- key.len, key.index, key.algo);
- WL_CONN("key \"%s\"\n", key.data);
- swap_key_from_BE(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key,
- sizeof(key));
- if (unlikely(err)) {
- WL_ERR("WLC_SET_KEY error (%d)\n", err);
+
+ if (sme->key_len == 0)
+ return 0;
+
+ sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
+ WL_CONN("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))
+ return 0;
+
+ if (sec->cipher_pairwise &
+ (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) {
+ memset(&key, 0, sizeof(key));
+ key.len = (u32) sme->key_len;
+ key.index = (u32) sme->key_idx;
+ if (key.len > sizeof(key.data)) {
+ WL_ERR("Too long key length (%u)\n", key.len);
+ return -EINVAL;
+ }
+ memcpy(key.data, sme->key, key.len);
+ key.flags = BRCMF_PRIMARY_KEY;
+ switch (sec->cipher_pairwise) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ key.algo = CRYPTO_ALGO_WEP1;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ key.algo = CRYPTO_ALGO_WEP128;
+ break;
+ default:
+ WL_ERR("Invalid algorithm (%d)\n",
+ sme->crypto.ciphers_pairwise[0]);
+ return -EINVAL;
+ }
+ /* Set the new key/index */
+ WL_CONN("key length (%d) key index (%d) algo (%d)\n",
+ key.len, key.index, key.algo);
+ WL_CONN("key \"%s\"\n", key.data);
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
+ return err;
+
+ if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
+ WL_CONN("set auth_type to shared key\n");
+ val = 1; /* shared key */
+ err = brcmf_dev_intvar_set(ndev, "auth", val);
+ if (err) {
+ WL_ERR("set auth failed (%d)\n", err);
return err;
}
- if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
- WL_CONN("set auth_type to shared key\n");
- val = 1; /* shared key */
- err = brcmf_dev_intvar_set(dev, "auth", val);
- if (unlikely(err)) {
- WL_ERR("set auth failed (%d)\n", err);
- return err;
- }
- }
}
}
return err;
}
static s32
-brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_connect_params *sme)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct ieee80211_channel *chan = sme->channel;
struct brcmf_join_params join_params;
size_t join_params_size;
+ struct brcmf_ssid ssid;
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
- if (unlikely(!sme->ssid)) {
+ if (!sme->ssid) {
WL_ERR("Invalid ssid\n");
return -EOPNOTSUPP;
}
@@ -1390,62 +1359,54 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len);
- err = brcmf_set_wpa_version(dev, sme);
+ err = brcmf_set_wpa_version(ndev, sme);
if (err) {
WL_ERR("wl_set_wpa_version failed (%d)\n", err);
goto done;
}
- err = brcmf_set_auth_type(dev, sme);
+ err = brcmf_set_auth_type(ndev, sme);
if (err) {
WL_ERR("wl_set_auth_type failed (%d)\n", err);
goto done;
}
- err = brcmf_set_set_cipher(dev, sme);
+ err = brcmf_set_set_cipher(ndev, sme);
if (err) {
WL_ERR("wl_set_set_cipher failed (%d)\n", err);
goto done;
}
- err = brcmf_set_key_mgmt(dev, sme);
+ err = brcmf_set_key_mgmt(ndev, sme);
if (err) {
WL_ERR("wl_set_key_mgmt failed (%d)\n", err);
goto done;
}
- err = brcmf_set_set_sharedkey(dev, sme);
+ err = brcmf_set_wep_sharedkey(ndev, sme);
if (err) {
- WL_ERR("wl_set_set_sharedkey failed (%d)\n", err);
+ WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err);
goto done;
}
- brcmf_update_prof(cfg_priv, NULL, sme->bssid, WL_PROF_BSSID);
- /*
- ** Join with specific BSSID and cached SSID
- ** If SSID is zero join based on BSSID only
- */
memset(&join_params, 0, sizeof(join_params));
- join_params_size = sizeof(join_params.ssid);
+ join_params_size = sizeof(join_params.ssid_le);
- 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 = cpu_to_le32(join_params.ssid.SSID_len);
- brcmf_update_prof(cfg_priv, NULL, &join_params.ssid, WL_PROF_SSID);
+ ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len);
+ memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len);
+ memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len);
+ join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len);
+ brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID);
- if (sme->bssid)
- memcpy(join_params.params.bssid, sme->bssid, ETH_ALEN);
- else
- memcpy(join_params.params.bssid, ether_bcast, ETH_ALEN);
+ memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN);
- if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
+ if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN)
WL_CONN("ssid \"%s\", len (%d)\n",
- join_params.ssid.SSID, join_params.ssid.SSID_len);
- }
+ ssid.SSID, ssid.SSID_len);
brcmf_ch_to_chanspec(cfg_priv->channel,
&join_params, &join_params_size);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_SSID,
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID,
&join_params, join_params_size);
if (err)
WL_ERR("WLC_SET_SSID failed (%d)\n", err);
@@ -1458,24 +1419,24 @@ done:
}
static s32
-brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
u16 reason_code)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
- struct brcmf_scb_val scbval;
+ struct brcmf_scb_val_le scbval;
s32 err = 0;
WL_TRACE("Enter. Reason code = %d\n", reason_code);
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
- scbval.val = reason_code;
memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN);
- scbval.val = cpu_to_le32(scbval.val);
- err = brcmf_dev_ioctl(dev, BRCMF_C_DISASSOC, &scbval,
- sizeof(struct brcmf_scb_val));
- if (unlikely(err))
+ scbval.val = cpu_to_le32(reason_code);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval,
+ sizeof(struct brcmf_scb_val_le));
+ if (err)
WL_ERR("error (%d)\n", err);
cfg_priv->link_up = false;
@@ -1496,7 +1457,8 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
s32 disable = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
@@ -1518,9 +1480,8 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
}
/* Make sure radio is off or on as far as software is concerned */
disable = WL_RADIO_SW_DISABLE << 16;
- disable = cpu_to_le32(disable);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_RADIO, &disable, sizeof(disable));
- if (unlikely(err))
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable);
+ if (err)
WL_ERR("WLC_SET_RADIO error (%d)\n", err);
if (dbm > 0xffff)
@@ -1528,8 +1489,8 @@ brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
else
txpwrmw = (u16) dbm;
err = brcmf_dev_intvar_set(ndev, "qtxpower",
- (s32) (brcmu_mw_to_qdbm(txpwrmw)));
- if (unlikely(err))
+ (s32) (brcmf_mw_to_qdbm(txpwrmw)));
+ if (err)
WL_ERR("qtxpower error (%d)\n", err);
cfg_priv->conf->tx_power = dbm;
@@ -1547,16 +1508,17 @@ static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
- if (unlikely(err)) {
+ if (err) {
WL_ERR("error (%d)\n", err);
goto done;
}
result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
- *dbm = (s32) brcmu_qdbm_to_mw(result);
+ *dbm = (s32) brcmf_qdbm_to_mw(result);
done:
WL_TRACE("Exit\n");
@@ -1564,31 +1526,30 @@ done:
}
static s32
-brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool unicast, bool multicast)
{
u32 index;
- s32 wsec;
+ u32 wsec;
s32 err = 0;
WL_TRACE("Enter\n");
WL_CONN("key index (%d)\n", key_idx);
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
+ if (err) {
WL_ERR("WLC_GET_WSEC error (%d)\n", err);
goto done;
}
- wsec = le32_to_cpu(wsec);
if (wsec & WEP_ENABLED) {
/* Just select a new current key */
- index = (u32) key_idx;
- index = cpu_to_le32(index);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY_PRIMARY, &index,
- sizeof(index));
- if (unlikely(err))
+ index = key_idx;
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY,
+ &index);
+ if (err)
WL_ERR("error (%d)\n", err);
}
done:
@@ -1597,10 +1558,11 @@ done:
}
static s32
-brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
+brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, const u8 *mac_addr, struct key_params *params)
{
struct brcmf_wsec_key key;
+ struct brcmf_wsec_key_le key_le;
s32 err = 0;
memset(&key, 0, sizeof(key));
@@ -1613,12 +1575,9 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
/* check for key index change */
if (key.len == 0) {
/* key delete */
- swap_key_from_BE(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
- WL_ERR("key delete error (%d)\n", err);
+ err = send_key_to_dongle(ndev, &key);
+ if (err)
return err;
- }
} else {
if (key.len > sizeof(key.data)) {
WL_ERR("Invalid key length (%d)\n", key.len);
@@ -1671,11 +1630,12 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
WL_ERR("Invalid cipher (0x%x)\n", params->cipher);
return -EINVAL;
}
- swap_key_from_BE(&key);
+ convert_key_from_CPU(&key, &key_le);
- brcmf_netdev_wait_pend8021x(dev);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
+ brcmf_netdev_wait_pend8021x(ndev);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le,
+ sizeof(key_le));
+ if (err) {
WL_ERR("WLC_SET_KEY error (%d)\n", err);
return err;
}
@@ -1684,7 +1644,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *dev,
}
static s32
-brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
@@ -1696,18 +1656,19 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
WL_TRACE("Enter\n");
WL_CONN("key index (%d)\n", key_idx);
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
if (mac_addr) {
WL_TRACE("Exit");
- return brcmf_add_keyext(wiphy, dev, key_idx, mac_addr, params);
+ return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
}
memset(&key, 0, sizeof(key));
key.len = (u32) params->key_len;
key.index = (u32) key_idx;
- if (unlikely(key.len > sizeof(key.data))) {
+ if (key.len > sizeof(key.data)) {
WL_ERR("Too long key length (%u)\n", key.len);
err = -EINVAL;
goto done;
@@ -1745,32 +1706,27 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
goto done;
}
- /* Set the new key/index */
- swap_key_from_BE(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
- WL_ERR("WLC_SET_KEY error (%d)\n", err);
+ err = send_key_to_dongle(ndev, &key); /* Set the new key/index */
+ if (err)
goto done;
- }
val = WEP_ENABLED;
- err = brcmf_dev_intvar_get(dev, "wsec", &wsec);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
+ if (err) {
WL_ERR("get wsec error (%d)\n", err);
goto done;
}
wsec &= ~(WEP_ENABLED);
wsec |= val;
- err = brcmf_dev_intvar_set(dev, "wsec", wsec);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+ if (err) {
WL_ERR("set wsec error (%d)\n", err);
goto done;
}
val = 1; /* assume shared key. otherwise 0 */
- val = cpu_to_le32(val);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_AUTH, &val, sizeof(val));
- if (unlikely(err))
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
+ if (err)
WL_ERR("WLC_SET_AUTH error (%d)\n", err);
done:
WL_TRACE("Exit\n");
@@ -1778,7 +1734,7 @@ done:
}
static s32
-brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct brcmf_wsec_key key;
@@ -1787,7 +1743,9 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
s32 wsec;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
@@ -1795,25 +1753,23 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
key.algo = CRYPTO_ALGO_OFF;
WL_CONN("key index (%d)\n", key_idx);
+
/* Set the new key/index */
- swap_key_from_BE(&key);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_KEY, &key, sizeof(key));
- if (unlikely(err)) {
+ err = send_key_to_dongle(ndev, &key);
+ if (err) {
if (err == -EINVAL) {
if (key.index >= DOT11_MAX_DEFAULT_KEYS)
/* we ignore this key index in this case */
WL_ERR("invalid key index (%d)\n", key_idx);
- } else
- WL_ERR("WLC_SET_KEY error (%d)\n", err);
-
+ }
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
goto done;
}
val = 0;
- err = brcmf_dev_intvar_get(dev, "wsec", &wsec);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_get(ndev, "wsec", &wsec);
+ if (err) {
WL_ERR("get wsec error (%d)\n", err);
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
@@ -1821,8 +1777,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}
wsec &= ~(WEP_ENABLED);
wsec |= val;
- err = brcmf_dev_intvar_set(dev, "wsec", wsec);
- if (unlikely(err)) {
+ err = brcmf_dev_intvar_set(ndev, "wsec", wsec);
+ if (err) {
WL_ERR("set wsec error (%d)\n", err);
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
@@ -1830,9 +1786,8 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}
val = 0; /* assume open key. otherwise 1 */
- val = cpu_to_le32(val);
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_AUTH, &val, sizeof(val));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val);
+ if (err) {
WL_ERR("WLC_SET_AUTH error (%d)\n", err);
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
@@ -1843,12 +1798,11 @@ done:
}
static s32
-brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback) (void *cookie, struct key_params * params))
{
struct key_params params;
- struct brcmf_wsec_key key;
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
struct brcmf_cfg80211_security *sec;
s32 wsec;
@@ -1856,23 +1810,18 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
WL_TRACE("Enter\n");
WL_CONN("key index (%d)\n", key_idx);
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
- memset(&key, 0, sizeof(key));
- key.index = key_idx;
- swap_key_to_BE(&key);
memset(&params, 0, sizeof(params));
- params.key_len = (u8) min_t(u8, WLAN_MAX_KEY_LEN, key.len);
- memcpy(params.key, key.data, params.key_len);
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_WSEC, &wsec, sizeof(wsec));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec);
+ if (err) {
WL_ERR("WLC_GET_WSEC error (%d)\n", err);
/* Ignore this error, may happen during DISASSOC */
err = -EAGAIN;
goto done;
}
- wsec = le32_to_cpu(wsec);
switch (wsec) {
case WEP_ENABLED:
sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC);
@@ -1906,30 +1855,29 @@ done:
static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
- struct net_device *dev, u8 key_idx)
+ struct net_device *ndev, u8 key_idx)
{
WL_INFO("Not supported\n");
- CHECK_SYS_UP();
return -EOPNOTSUPP;
}
static s32
-brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
u8 *mac, struct station_info *sinfo)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
- struct brcmf_scb_val scb_val;
+ struct brcmf_scb_val_le scb_val;
int rssi;
s32 rate;
s32 err = 0;
u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID);
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
- if (unlikely
- (memcmp(mac, bssid, ETH_ALEN))) {
+ if (memcmp(mac, bssid, ETH_ALEN)) {
WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X"
"wl_bssid-%X:%X:%X:%X:%X:%X\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
@@ -1940,23 +1888,22 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
}
/* Report the current tx rate */
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_RATE, &rate, sizeof(rate));
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate);
if (err) {
WL_ERR("Could not get rate (%d)\n", err);
} else {
- rate = le32_to_cpu(rate);
sinfo->filled |= STATION_INFO_TX_BITRATE;
sinfo->txrate.legacy = rate * 5;
WL_CONN("Rate %d Mbps\n", rate / 2);
}
if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) {
- scb_val.val = 0;
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_RSSI, &scb_val,
- sizeof(struct brcmf_scb_val));
- if (unlikely(err)) {
+ scb_val.val = cpu_to_le32(0);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val,
+ sizeof(struct brcmf_scb_val_le));
+ if (err)
WL_ERR("Could not get rssi (%d)\n", err);
- }
+
rssi = le32_to_cpu(scb_val.val);
sinfo->filled |= STATION_INFO_SIGNAL;
sinfo->signal = rssi;
@@ -1969,63 +1916,51 @@ done:
}
static s32
-brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
bool enabled, s32 timeout)
{
s32 pm;
s32 err = 0;
+ struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+
+ /*
+ * Powersave enable/disable request is coming from the
+ * cfg80211 even before the interface is up. In that
+ * scenario, driver will be storing the power save
+ * preference in cfg_priv struct to apply this to
+ * FW later while initializing the dongle
+ */
+ cfg_priv->pwr_save = enabled;
+ if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) {
+
+ WL_INFO("Device is not ready,"
+ "storing the value in cfg_priv struct\n");
+ goto done;
+ }
pm = enabled ? PM_FAST : PM_OFF;
- pm = cpu_to_le32(pm);
WL_INFO("power save %s\n", (pm ? "enabled" : "disabled"));
- err = brcmf_dev_ioctl(dev, BRCMF_C_SET_PM, &pm, sizeof(pm));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm);
+ if (err) {
if (err == -ENODEV)
WL_ERR("net_device is not ready yet\n");
else
WL_ERR("error (%d)\n", err);
}
+done:
WL_TRACE("Exit\n");
return err;
}
-static __used u32 brcmf_find_msb(u16 bit16)
-{
- u32 ret = 0;
-
- if (bit16 & 0xff00) {
- ret += 8;
- bit16 >>= 8;
- }
-
- if (bit16 & 0xf0) {
- ret += 4;
- bit16 >>= 4;
- }
-
- if (bit16 & 0xc) {
- ret += 2;
- bit16 >>= 2;
- }
-
- if (bit16 & 2)
- ret += bit16 & 2;
- else if (bit16)
- ret += bit16;
-
- return ret;
-}
-
static s32
-brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
const u8 *addr,
const struct cfg80211_bitrate_mask *mask)
{
- struct wl_rateset rateset;
+ struct brcm_rateset_le rateset_le;
s32 rate;
s32 val;
s32 err_bg;
@@ -2034,28 +1969,28 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
/* addr param is always NULL. ignore it */
/* Get current rateset */
- err = brcmf_dev_ioctl(dev, BRCM_GET_CURR_RATESET, &rateset,
- sizeof(rateset));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le,
+ sizeof(rateset_le));
+ if (err) {
WL_ERR("could not get current rateset (%d)\n", err);
goto done;
}
- rateset.count = le32_to_cpu(rateset.count);
-
- legacy = brcmf_find_msb(mask->control[IEEE80211_BAND_2GHZ].legacy);
+ legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF);
if (!legacy)
- legacy = brcmf_find_msb(mask->control[IEEE80211_BAND_5GHZ].legacy);
+ legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy &
+ 0xFFFF);
val = wl_g_rates[legacy - 1].bitrate * 100000;
- if (val < rateset.count)
+ if (val < le32_to_cpu(rateset_le.count))
/* Select rate by rateset index */
- rate = rateset.rates[val] & 0x7f;
+ rate = rateset_le.rates[val] & 0x7f;
else
/* Specified rate in bps */
rate = val / 500000;
@@ -2067,9 +2002,9 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev,
* Set rate override,
* Since the is a/b/g-blind, both a/bg_rate are enforced.
*/
- err_bg = brcmf_dev_intvar_set(dev, "bg_rate", rate);
- err_a = brcmf_dev_intvar_set(dev, "a_rate", rate);
- if (unlikely(err_bg && err_a)) {
+ err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate);
+ err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate);
+ if (err_bg && err_a) {
WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a);
err = err_bg | err_a;
}
@@ -2079,6 +2014,483 @@ done:
return err;
}
+static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
+ struct brcmf_bss_info *bi)
+{
+ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
+ struct ieee80211_channel *notify_channel;
+ struct cfg80211_bss *bss;
+ struct ieee80211_supported_band *band;
+ s32 err = 0;
+ u16 channel;
+ u32 freq;
+ u64 notify_timestamp;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) {
+ WL_ERR("Bss info is larger than buffer. Discarding\n");
+ return 0;
+ }
+
+ channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
+ notify_capability = le16_to_cpu(bi->capability);
+ notify_interval = le16_to_cpu(bi->beacon_period);
+ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+ notify_ielen = le32_to_cpu(bi->ie_length);
+ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+ WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
+ bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
+ WL_CONN("Channel: %d(%d)\n", channel, freq);
+ WL_CONN("Capability: %X\n", notify_capability);
+ WL_CONN("Beacon interval: %d\n", notify_interval);
+ WL_CONN("Signal: %d\n", notify_signal);
+ WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
+
+ bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
+ notify_timestamp, notify_capability, notify_interval, notify_ie,
+ notify_ielen, notify_signal, GFP_KERNEL);
+
+ if (!bss) {
+ WL_ERR("cfg80211_inform_bss_frame error\n");
+ return -EINVAL;
+ }
+
+ return err;
+}
+
+static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_scan_results *bss_list;
+ struct brcmf_bss_info *bi = NULL; /* must be initialized */
+ s32 err = 0;
+ int i;
+
+ bss_list = cfg_priv->bss_list;
+ if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
+ WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
+ bss_list->version);
+ return -EOPNOTSUPP;
+ }
+ WL_SCAN("scanned AP count (%d)\n", bss_list->count);
+ for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
+ bi = next_bss(bss_list, bi);
+ err = brcmf_inform_single_bss(cfg_priv, bi);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev, const u8 *bssid)
+{
+ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
+ struct ieee80211_channel *notify_channel;
+ struct brcmf_bss_info *bi = NULL;
+ struct ieee80211_supported_band *band;
+ u8 *buf = NULL;
+ s32 err = 0;
+ u16 channel;
+ u32 freq;
+ u64 notify_timestamp;
+ u16 notify_capability;
+ u16 notify_interval;
+ u8 *notify_ie;
+ size_t notify_ielen;
+ s32 notify_signal;
+
+ WL_TRACE("Enter\n");
+
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto CleanUp;
+ }
+
+ *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+ if (err) {
+ WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
+ goto CleanUp;
+ }
+
+ bi = (struct brcmf_bss_info *)(buf + 4);
+
+ channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
+
+ if (channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
+ notify_capability = le16_to_cpu(bi->capability);
+ notify_interval = le16_to_cpu(bi->beacon_period);
+ notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
+ notify_ielen = le32_to_cpu(bi->ie_length);
+ notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
+
+ WL_CONN("channel: %d(%d)\n", channel, freq);
+ WL_CONN("capability: %X\n", notify_capability);
+ WL_CONN("beacon interval: %d\n", notify_interval);
+ WL_CONN("signal: %d\n", notify_signal);
+ WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
+
+ cfg80211_inform_bss(wiphy, notify_channel, bssid,
+ notify_timestamp, notify_capability, notify_interval,
+ notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
+
+CleanUp:
+
+ kfree(buf);
+
+ WL_TRACE("Exit\n");
+
+ return err;
+}
+
+static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ return cfg_priv->conf->mode == WL_MODE_IBSS;
+}
+
+/*
+ * Traverse a string of 1-byte tag/1-byte length/variable-length value
+ * triples, returning a pointer to the substring whose first element
+ * matches tag
+ */
+static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
+{
+ struct brcmf_tlv *elt;
+ int totlen;
+
+ elt = (struct brcmf_tlv *) buf;
+ totlen = buflen;
+
+ /* find tagged parameter */
+ while (totlen >= 2) {
+ int len = elt->len;
+
+ /* validate remaining totlen */
+ if ((elt->id == key) && (totlen >= (len + 2)))
+ return elt;
+
+ elt = (struct brcmf_tlv *) ((u8 *) elt + (len + 2));
+ totlen -= (len + 2);
+ }
+
+ return NULL;
+}
+
+static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_bss_info *bi;
+ struct brcmf_ssid *ssid;
+ struct brcmf_tlv *tim;
+ u16 beacon_interval;
+ u8 dtim_period;
+ size_t ie_len;
+ u8 *ie;
+ s32 err = 0;
+
+ WL_TRACE("Enter\n");
+ if (brcmf_is_ibssmode(cfg_priv))
+ return err;
+
+ ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID);
+
+ *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
+ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO,
+ cfg_priv->extra_buf, WL_EXTRA_BUF_MAX);
+ if (err) {
+ WL_ERR("Could not get bss info %d\n", err);
+ goto update_bss_info_out;
+ }
+
+ bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4);
+ err = brcmf_inform_single_bss(cfg_priv, bi);
+ if (err)
+ goto update_bss_info_out;
+
+ ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset);
+ ie_len = le32_to_cpu(bi->ie_length);
+ beacon_interval = le16_to_cpu(bi->beacon_period);
+
+ tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
+ if (tim)
+ dtim_period = tim->data[1];
+ else {
+ /*
+ * active scan was done so we could not get dtim
+ * information out of probe response.
+ * so we speficially query dtim information to dongle.
+ */
+ u32 var;
+ err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv),
+ "dtim_assoc", &var);
+ if (err) {
+ WL_ERR("wl dtim_assoc failed (%d)\n", err);
+ goto update_bss_info_out;
+ }
+ dtim_period = (u8)var;
+ }
+
+ brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT);
+ brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
+
+update_bss_info_out:
+ WL_TRACE("Exit");
+ return err;
+}
+
+static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+ struct brcmf_ssid ssid;
+
+ if (cfg_priv->iscan_on) {
+ iscan->state = WL_ISCAN_STATE_IDLE;
+
+ if (iscan->timer_on) {
+ del_timer_sync(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+
+ cancel_work_sync(&iscan->work);
+
+ /* Abort iscan running in FW */
+ memset(&ssid, 0, sizeof(ssid));
+ brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
+ }
+}
+
+static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
+ bool aborted)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
+ struct net_device *ndev = cfg_to_ndev(cfg_priv);
+
+ if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
+ WL_ERR("Scan complete while device not scanning\n");
+ return;
+ }
+ if (cfg_priv->scan_request) {
+ WL_SCAN("ISCAN Completed scan: %s\n",
+ aborted ? "Aborted" : "Done");
+ cfg80211_scan_done(cfg_priv->scan_request, aborted);
+ brcmf_set_mpc(ndev, 1);
+ cfg_priv->scan_request = NULL;
+ }
+ cfg_priv->iscan_kickstart = false;
+}
+
+static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
+{
+ if (iscan->state != WL_ISCAN_STATE_IDLE) {
+ WL_SCAN("wake up iscan\n");
+ schedule_work(&iscan->work);
+ return 0;
+ }
+
+ return -EIO;
+}
+
+static s32
+brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
+ struct brcmf_scan_results **bss_list)
+{
+ struct brcmf_iscan_results list;
+ struct brcmf_scan_results *results;
+ struct brcmf_scan_results_le *results_le;
+ struct brcmf_iscan_results *list_buf;
+ s32 err = 0;
+
+ memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
+ list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
+ results = &list_buf->results;
+ results_le = &list_buf->results_le;
+ results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE;
+ results->version = 0;
+ results->count = 0;
+
+ memset(&list, 0, sizeof(list));
+ list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
+ err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list,
+ BRCMF_ISCAN_RESULTS_FIXED_SIZE,
+ iscan->scan_buf, WL_ISCAN_BUF_MAX);
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+ results->buflen = le32_to_cpu(results_le->buflen);
+ results->version = le32_to_cpu(results_le->version);
+ results->count = le32_to_cpu(results_le->count);
+ WL_SCAN("results->count = %d\n", results_le->count);
+ WL_SCAN("results->buflen = %d\n", results_le->buflen);
+ *status = le32_to_cpu(list_buf->status_le);
+ WL_SCAN("status = %d\n", *status);
+ *bss_list = results;
+
+ return err;
+}
+
+static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ brcmf_inform_bss(cfg_priv);
+ brcmf_notify_iscan_complete(iscan, false);
+
+ return err;
+}
+
+static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ /* Reschedule the timer */
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
+ iscan->timer_on = 1;
+
+ return err;
+}
+
+static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ brcmf_inform_bss(cfg_priv);
+ brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
+ /* Reschedule the timer */
+ mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
+ iscan->timer_on = 1;
+
+ return err;
+}
+
+static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ s32 err = 0;
+
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ brcmf_notify_iscan_complete(iscan, true);
+
+ return err;
+}
+
+static void brcmf_cfg80211_iscan_handler(struct work_struct *work)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan =
+ container_of(work, struct brcmf_cfg80211_iscan_ctrl,
+ work);
+ struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
+ struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
+ u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
+
+ if (iscan->timer_on) {
+ del_timer_sync(&iscan->timer);
+ iscan->timer_on = 0;
+ }
+
+ if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) {
+ status = BRCMF_SCAN_RESULTS_ABORTED;
+ WL_ERR("Abort iscan\n");
+ }
+
+ el->handler[status](cfg_priv);
+}
+
+static void brcmf_iscan_timer(unsigned long data)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan =
+ (struct brcmf_cfg80211_iscan_ctrl *)data;
+
+ if (iscan) {
+ iscan->timer_on = 0;
+ WL_SCAN("timer expired\n");
+ brcmf_wakeup_iscan(iscan);
+ }
+}
+
+static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+
+ if (cfg_priv->iscan_on) {
+ iscan->state = WL_ISCAN_STATE_IDLE;
+ INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
+ }
+
+ return 0;
+}
+
+static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
+{
+ memset(el, 0, sizeof(*el));
+ el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
+ el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
+ el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
+ el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
+ el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
+}
+
+static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+ int err = 0;
+
+ if (cfg_priv->iscan_on) {
+ iscan->ndev = cfg_to_ndev(cfg_priv);
+ brcmf_init_iscan_eloop(&iscan->el);
+ iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
+ init_timer(&iscan->timer);
+ iscan->timer.data = (unsigned long) iscan;
+ iscan->timer.function = brcmf_iscan_timer;
+ err = brcmf_invoke_iscan(cfg_priv);
+ if (!err)
+ iscan->data = cfg_priv;
+ }
+
+ return err;
+}
+
+static void brcmf_delay(u32 ms)
+{
+ if (ms < 1000 / HZ) {
+ cond_resched();
+ mdelay(ms);
+ } else {
+ msleep(ms);
+ }
+}
+
static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
@@ -2090,10 +2502,6 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
*/
WL_TRACE("Enter\n");
-#if defined(CONFIG_PM_SLEEP)
- atomic_set(&brcmf_mmc_suspend, false);
-#endif /* defined(CONFIG_PM_SLEEP) */
-
if (test_bit(WL_STATUS_READY, &cfg_priv->status))
brcmf_invoke_iscan(wiphy_to_cfg(wiphy));
@@ -2131,9 +2539,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
* generated due to DISASSOC call to the fw to keep
* the state fw and WPA_Supplicant state consistent
*/
- rtnl_unlock();
brcmf_delay(500);
- rtnl_lock();
}
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
@@ -2155,81 +2561,123 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
brcmf_set_mpc(ndev, 1);
}
-#if defined(CONFIG_PM_SLEEP)
- atomic_set(&brcmf_mmc_suspend, true);
-#endif /* defined(CONFIG_PM_SLEEP) */
-
WL_TRACE("Exit\n");
return 0;
}
static __used s32
-brcmf_update_pmklist(struct net_device *dev,
+brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ u32 buflen;
+
+ buflen = brcmf_c_mkiovar(name, buf, len, cfg_priv->dcmd_buf,
+ WL_DCMD_LEN_MAX);
+ BUG_ON(!buflen);
+
+ return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf,
+ buflen);
+}
+
+static s32
+brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf,
+ s32 buf_len)
+{
+ struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
+ u32 len;
+ s32 err = 0;
+
+ len = brcmf_c_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf,
+ WL_DCMD_LEN_MAX);
+ BUG_ON(!len);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf,
+ WL_DCMD_LEN_MAX);
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+ memcpy(buf, cfg_priv->dcmd_buf, buf_len);
+
+ return err;
+}
+
+static __used s32
+brcmf_update_pmklist(struct net_device *ndev,
struct brcmf_cfg80211_pmk_list *pmk_list, s32 err)
{
int i, j;
+ int pmkid_len;
- WL_CONN("No of elements %d\n", pmk_list->pmkids.npmkid);
- for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
+ pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid);
+
+ WL_CONN("No of elements %d\n", pmkid_len);
+ for (i = 0; i < pmkid_len; i++) {
WL_CONN("PMKID[%d]: %pM =\n", i,
&pmk_list->pmkids.pmkid[i].BSSID);
for (j = 0; j < WLAN_PMKID_LEN; j++)
WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]);
}
- if (likely(!err))
- brcmf_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
+ if (!err)
+ brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list,
sizeof(*pmk_list));
return err;
}
static s32
-brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_pmksa *pmksa)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
- struct _pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids;
+ struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids;
s32 err = 0;
int i;
+ int pmkid_len;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
- for (i = 0; i < pmkids->npmkid; i++)
+ pmkid_len = le32_to_cpu(pmkids->npmkid);
+ for (i = 0; i < pmkid_len; i++)
if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN))
break;
if (i < WL_NUM_PMKIDS_MAX) {
memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN);
memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
- if (i == pmkids->npmkid)
- pmkids->npmkid++;
+ if (i == pmkid_len) {
+ pmkid_len++;
+ pmkids->npmkid = cpu_to_le32(pmkid_len);
+ }
} else
err = -EINVAL;
WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
- pmkids->pmkid[pmkids->npmkid].BSSID);
+ pmkids->pmkid[pmkid_len].BSSID);
for (i = 0; i < WLAN_PMKID_LEN; i++)
- WL_CONN("%02x\n", pmkids->pmkid[pmkids->npmkid].PMKID[i]);
+ WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]);
- err = brcmf_update_pmklist(dev, cfg_priv->pmk_list, err);
+ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
WL_TRACE("Exit\n");
return err;
}
static s32
-brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
+brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_pmksa *pmksa)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
- struct _pmkid_list pmkid;
+ struct pmkid_list pmkid;
s32 err = 0;
- int i;
+ int i, pmkid_len;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
+
memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN);
memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
@@ -2238,17 +2686,18 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
for (i = 0; i < WLAN_PMKID_LEN; i++)
WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]);
- for (i = 0; i < cfg_priv->pmk_list->pmkids.npmkid; i++)
+ pmkid_len = le32_to_cpu(cfg_priv->pmk_list->pmkids.npmkid);
+ for (i = 0; i < pmkid_len; i++)
if (!memcmp
(pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID,
ETH_ALEN))
break;
- if ((cfg_priv->pmk_list->pmkids.npmkid > 0)
- && (i < cfg_priv->pmk_list->pmkids.npmkid)) {
+ if ((pmkid_len > 0)
+ && (i < pmkid_len)) {
memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0,
- sizeof(pmkid_t));
- for (; i < (cfg_priv->pmk_list->pmkids.npmkid - 1); i++) {
+ sizeof(struct pmkid));
+ for (; i < (pmkid_len - 1); i++) {
memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID,
&cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID,
ETH_ALEN);
@@ -2256,11 +2705,11 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
&cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID,
WLAN_PMKID_LEN);
}
- cfg_priv->pmk_list->pmkids.npmkid--;
+ cfg_priv->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1);
} else
err = -EINVAL;
- err = brcmf_update_pmklist(dev, cfg_priv->pmk_list, err);
+ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
WL_TRACE("Exit\n");
return err;
@@ -2268,16 +2717,17 @@ brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
}
static s32
-brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
+brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
{
struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy);
s32 err = 0;
WL_TRACE("Enter\n");
- CHECK_SYS_UP();
+ if (!check_sys_up(wiphy))
+ return -EIO;
memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list));
- err = brcmf_update_pmklist(dev, cfg_priv->pmk_list, err);
+ err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err);
WL_TRACE("Exit\n");
return err;
@@ -2326,25 +2776,24 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
}
static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
- struct device *dev)
+ struct device *ndev)
{
struct wireless_dev *wdev;
s32 err = 0;
wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
- if (unlikely(!wdev)) {
- WL_ERR("Could not allocate wireless device\n");
+ if (!wdev)
return ERR_PTR(-ENOMEM);
- }
+
wdev->wiphy =
wiphy_new(&wl_cfg80211_ops,
sizeof(struct brcmf_cfg80211_priv) + sizeof_iface);
- if (unlikely(!wdev->wiphy)) {
+ if (!wdev->wiphy) {
WL_ERR("Couldn not allocate wiphy device\n");
err = -ENOMEM;
goto wiphy_new_out;
}
- set_wiphy_dev(wdev->wiphy, dev);
+ set_wiphy_dev(wdev->wiphy, ndev);
wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX;
wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
wdev->wiphy->interface_modes =
@@ -2360,16 +2809,12 @@ static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface,
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wdev->wiphy->cipher_suites = __wl_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
-#ifndef WL_POWERSAVE_DISABLED
wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power
* save mode
* by default
*/
-#else
- wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-#endif /* !WL_POWERSAVE_DISABLED */
err = wiphy_register(wdev->wiphy);
- if (unlikely(err < 0)) {
+ if (err < 0) {
WL_ERR("Couldn not register wiphy device (%d)\n", err);
goto wiphy_register_out;
}
@@ -2386,175 +2831,16 @@ wiphy_new_out:
static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv)
{
- struct wireless_dev *wdev = cfg_to_wdev(cfg_priv);
+ struct wireless_dev *wdev = cfg_priv->wdev;
- if (unlikely(!wdev)) {
+ if (!wdev) {
WL_ERR("wdev is invalid\n");
return;
}
wiphy_unregister(wdev->wiphy);
wiphy_free(wdev->wiphy);
kfree(wdev);
- cfg_to_wdev(cfg_priv) = NULL;
-}
-
-static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_scan_results *bss_list;
- struct brcmf_bss_info *bi = NULL; /* must be initialized */
- s32 err = 0;
- int i;
-
- bss_list = cfg_priv->bss_list;
- if (unlikely(bss_list->version != BRCMF_BSS_INFO_VERSION)) {
- WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
- bss_list->version);
- return -EOPNOTSUPP;
- }
- WL_SCAN("scanned AP count (%d)\n", bss_list->count);
- bi = next_bss(bss_list, bi);
- for_each_bss(bss_list, bi, i) {
- err = brcmf_inform_single_bss(cfg_priv, bi);
- if (unlikely(err))
- break;
- }
- return err;
-}
-
-
-static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
- struct brcmf_bss_info *bi)
-{
- struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
- struct ieee80211_channel *notify_channel;
- struct cfg80211_bss *bss;
- struct ieee80211_supported_band *band;
- s32 err = 0;
- u16 channel;
- u32 freq;
- u64 notify_timestamp;
- u16 notify_capability;
- u16 notify_interval;
- u8 *notify_ie;
- size_t notify_ielen;
- s32 notify_signal;
-
- if (unlikely(le32_to_cpu(bi->length) > WL_BSS_INFO_MAX)) {
- WL_ERR("Bss info is larger than buffer. Discarding\n");
- return 0;
- }
-
- channel = bi->ctl_ch ? bi->ctl_ch :
- CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
-
- if (channel <= CH_MAX_2G_CHANNEL)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
- freq = ieee80211_channel_to_frequency(channel, band->band);
- notify_channel = ieee80211_get_channel(wiphy, freq);
-
- notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
- notify_capability = le16_to_cpu(bi->capability);
- notify_interval = le16_to_cpu(bi->beacon_period);
- notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
- notify_ielen = le16_to_cpu(bi->ie_length);
- notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
-
- WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- bi->BSSID[0], bi->BSSID[1], bi->BSSID[2],
- bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]);
- WL_CONN("Channel: %d(%d)\n", channel, freq);
- WL_CONN("Capability: %X\n", notify_capability);
- WL_CONN("Beacon interval: %d\n", notify_interval);
- WL_CONN("Signal: %d\n", notify_signal);
- WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
-
- bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID,
- notify_timestamp, notify_capability, notify_interval, notify_ie,
- notify_ielen, notify_signal, GFP_KERNEL);
-
- if (unlikely(!bss)) {
- WL_ERR("cfg80211_inform_bss_frame error\n");
- return -EINVAL;
- }
-
- return err;
-}
-
-static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *dev, const u8 *bssid)
-{
- struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
- struct ieee80211_channel *notify_channel;
- struct brcmf_bss_info *bi = NULL;
- struct ieee80211_supported_band *band;
- u8 *buf = NULL;
- s32 err = 0;
- u16 channel;
- u32 freq;
- u64 notify_timestamp;
- u16 notify_capability;
- u16 notify_interval;
- u8 *notify_ie;
- size_t notify_ielen;
- s32 notify_signal;
-
- WL_TRACE("Enter\n");
-
- buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
- if (buf == NULL) {
- WL_ERR("kzalloc() failed\n");
- err = -ENOMEM;
- goto CleanUp;
- }
-
- *(u32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
-
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
- if (unlikely(err)) {
- WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err);
- goto CleanUp;
- }
-
- bi = (struct brcmf_bss_info *)(buf + 4);
-
- channel = bi->ctl_ch ? bi->ctl_ch :
- CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
-
- if (channel <= CH_MAX_2G_CHANNEL)
- band = wiphy->bands[IEEE80211_BAND_2GHZ];
- else
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
-
- freq = ieee80211_channel_to_frequency(channel, band->band);
- notify_channel = ieee80211_get_channel(wiphy, freq);
-
- notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */
- notify_capability = le16_to_cpu(bi->capability);
- notify_interval = le16_to_cpu(bi->beacon_period);
- notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset);
- notify_ielen = le16_to_cpu(bi->ie_length);
- notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100;
-
- WL_CONN("channel: %d(%d)\n", channel, freq);
- WL_CONN("capability: %X\n", notify_capability);
- WL_CONN("beacon interval: %d\n", notify_interval);
- WL_CONN("signal: %d\n", notify_signal);
- WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
-
- cfg80211_inform_bss(wiphy, notify_channel, bssid,
- notify_timestamp, notify_capability, notify_interval,
- notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
-
-CleanUp:
-
- kfree(buf);
-
- WL_TRACE("Exit\n");
-
- return err;
+ cfg_priv->wdev = NULL;
}
static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv,
@@ -2606,110 +2892,22 @@ static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv,
return false;
}
-static s32
-brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data)
-{
- s32 err = 0;
-
- if (brcmf_is_linkup(cfg_priv, e)) {
- WL_CONN("Linkup\n");
- if (brcmf_is_ibssmode(cfg_priv)) {
- brcmf_update_prof(cfg_priv, NULL, (void *)e->addr,
- WL_PROF_BSSID);
- wl_inform_ibss(cfg_priv, ndev, e->addr);
- cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
- clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
- set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
- } else
- brcmf_bss_connect_done(cfg_priv, ndev, e, data, true);
- } else if (brcmf_is_linkdown(cfg_priv, e)) {
- WL_CONN("Linkdown\n");
- if (brcmf_is_ibssmode(cfg_priv)) {
- clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
- if (test_and_clear_bit(WL_STATUS_CONNECTED,
- &cfg_priv->status))
- brcmf_link_down(cfg_priv);
- } else {
- brcmf_bss_connect_done(cfg_priv, ndev, e, data, false);
- if (test_and_clear_bit(WL_STATUS_CONNECTED,
- &cfg_priv->status)) {
- cfg80211_disconnected(ndev, 0, NULL, 0,
- GFP_KERNEL);
- brcmf_link_down(cfg_priv);
- }
- }
- brcmf_init_prof(cfg_priv->profile);
- } else if (brcmf_is_nonetwork(cfg_priv, e)) {
- if (brcmf_is_ibssmode(cfg_priv))
- clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
- else
- brcmf_bss_connect_done(cfg_priv, ndev, e, data, false);
- }
-
- return err;
-}
-
-static s32
-brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv,
- struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data)
-{
- s32 err = 0;
- u32 event = be32_to_cpu(e->event_type);
- u32 status = be32_to_cpu(e->status);
-
- if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
- if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status))
- brcmf_bss_roaming_done(cfg_priv, ndev, e, data);
- else
- brcmf_bss_connect_done(cfg_priv, ndev, e, data, true);
- }
-
- return err;
-}
-
-static __used s32
-brcmf_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
-{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
- u32 buflen;
-
- buflen = brcmu_mkiovar(name, buf, len, cfg_priv->ioctl_buf,
- WL_IOCTL_LEN_MAX);
- BUG_ON(!buflen);
-
- return brcmf_dev_ioctl(dev, BRCMF_C_SET_VAR, cfg_priv->ioctl_buf,
- buflen);
-}
-
-static s32
-brcmf_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
- s32 buf_len)
+static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
{
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(dev);
- u32 len;
- s32 err = 0;
-
- len = brcmu_mkiovar(name, NULL, 0, cfg_priv->ioctl_buf,
- WL_IOCTL_LEN_MAX);
- BUG_ON(!len);
- err = brcmf_dev_ioctl(dev, BRCMF_C_GET_VAR, (void *)cfg_priv->ioctl_buf,
- WL_IOCTL_LEN_MAX);
- if (unlikely(err)) {
- WL_ERR("error (%d)\n", err);
- return err;
- }
- memcpy(buf, cfg_priv->ioctl_buf, buf_len);
+ struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
- return err;
+ kfree(conn_info->req_ie);
+ conn_info->req_ie = NULL;
+ conn_info->req_ie_len = 0;
+ kfree(conn_info->resp_ie);
+ conn_info->resp_ie = NULL;
+ conn_info->resp_ie_len = 0;
}
static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
{
struct net_device *ndev = cfg_to_ndev(cfg_priv);
- struct brcmf_cfg80211_assoc_ielen *assoc_info;
+ struct brcmf_cfg80211_assoc_ielen_le *assoc_info;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
u32 req_len;
u32 resp_len;
@@ -2719,18 +2917,19 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf,
WL_ASSOC_INFO_MAX);
- if (unlikely(err)) {
+ if (err) {
WL_ERR("could not get assoc info (%d)\n", err);
return err;
}
- assoc_info = (struct brcmf_cfg80211_assoc_ielen *)cfg_priv->extra_buf;
- req_len = assoc_info->req_len;
- resp_len = assoc_info->resp_len;
+ assoc_info =
+ (struct brcmf_cfg80211_assoc_ielen_le *)cfg_priv->extra_buf;
+ req_len = le32_to_cpu(assoc_info->req_len);
+ resp_len = le32_to_cpu(assoc_info->resp_len);
if (req_len) {
err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies",
cfg_priv->extra_buf,
WL_ASSOC_INFO_MAX);
- if (unlikely(err)) {
+ if (err) {
WL_ERR("could not get assoc req (%d)\n", err);
return err;
}
@@ -2746,7 +2945,7 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies",
cfg_priv->extra_buf,
WL_ASSOC_INFO_MAX);
- if (unlikely(err)) {
+ if (err) {
WL_ERR("could not get assoc resp (%d)\n", err);
return err;
}
@@ -2764,121 +2963,19 @@ static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
return err;
}
-static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
-
- kfree(conn_info->req_ie);
- conn_info->req_ie = NULL;
- conn_info->req_ie_len = 0;
- kfree(conn_info->resp_ie);
- conn_info->resp_ie = NULL;
- conn_info->resp_ie_len = 0;
-}
-
-
-static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params,
- size_t *join_params_size)
-{
- chanspec_t chanspec = 0;
-
- if (ch != 0) {
- join_params->params.chanspec_num = 1;
- join_params->params.chanspec_list[0] = ch;
-
- if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
- chanspec |= WL_CHANSPEC_BAND_2G;
- else
- chanspec |= WL_CHANSPEC_BAND_5G;
-
- chanspec |= WL_CHANSPEC_BW_20;
- chanspec |= WL_CHANSPEC_CTL_SB_NONE;
-
- *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE +
- join_params->params.chanspec_num * sizeof(chanspec_t);
-
- join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
- join_params->params.chanspec_list[0] |= chanspec;
- join_params->params.chanspec_list[0] =
- cpu_to_le16(join_params->params.chanspec_list[0]);
-
- join_params->params.chanspec_num =
- cpu_to_le32(join_params->params.chanspec_num);
-
- WL_CONN("join_params->params.chanspec_list[0]= %#X,"
- "channel %d, chanspec %#X\n",
- join_params->params.chanspec_list[0], ch, chanspec);
- }
-}
-
-static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_bss_info *bi;
- struct brcmf_ssid *ssid;
- struct brcmu_tlv *tim;
- u16 beacon_interval;
- u8 dtim_period;
- size_t ie_len;
- u8 *ie;
- s32 err = 0;
-
- WL_TRACE("Enter\n");
- if (brcmf_is_ibssmode(cfg_priv))
- return err;
-
- ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID);
-
- *(u32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX);
- err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO,
- cfg_priv->extra_buf, WL_EXTRA_BUF_MAX);
- if (unlikely(err)) {
- WL_ERR("Could not get bss info %d\n", err);
- goto update_bss_info_out;
- }
-
- bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4);
- err = brcmf_inform_single_bss(cfg_priv, bi);
- if (unlikely(err))
- goto update_bss_info_out;
-
- ie = ((u8 *)bi) + bi->ie_offset;
- ie_len = bi->ie_length;
- beacon_interval = cpu_to_le16(bi->beacon_period);
-
- tim = brcmu_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
- if (tim)
- dtim_period = tim->data[1];
- else {
- /*
- * active scan was done so we could not get dtim
- * information out of probe response.
- * so we speficially query dtim information to dongle.
- */
- u32 var;
- err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv),
- "dtim_assoc", &var);
- if (unlikely(err)) {
- WL_ERR("wl dtim_assoc failed (%d)\n", err);
- goto update_bss_info_out;
- }
- dtim_period = (u8)var;
- }
-
- brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT);
- brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
-
-update_bss_info_out:
- WL_TRACE("Exit");
- return err;
-}
-
static s32
brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev,
- const struct brcmf_event_msg *e, void *data)
+ const struct brcmf_event_msg *e)
{
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
+ struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
+ struct brcmf_channel_info_le channel_le;
+ struct ieee80211_channel *notify_channel;
+ struct ieee80211_supported_band *band;
+ u32 freq;
s32 err = 0;
+ u32 target_channel;
WL_TRACE("Enter\n");
@@ -2886,7 +2983,21 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID);
brcmf_update_bss_info(cfg_priv);
- cfg80211_roamed(ndev, NULL,
+ brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le,
+ sizeof(channel_le));
+
+ target_channel = le32_to_cpu(channel_le.target_channel);
+ WL_CONN("Roamed to channel %d\n", target_channel);
+
+ if (target_channel <= CH_MAX_2G_CHANNEL)
+ band = wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ band = wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ freq = ieee80211_channel_to_frequency(target_channel, band->band);
+ notify_channel = ieee80211_get_channel(wiphy, freq);
+
+ cfg80211_roamed(ndev, notify_channel,
(u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID),
conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
@@ -2900,7 +3011,7 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv,
static s32
brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev, const struct brcmf_event_msg *e,
- void *data, bool completed)
+ bool completed)
{
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv);
s32 err = 0;
@@ -2934,6 +3045,57 @@ brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv,
}
static s32
+brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ s32 err = 0;
+
+ if (brcmf_is_linkup(cfg_priv, e)) {
+ WL_CONN("Linkup\n");
+ if (brcmf_is_ibssmode(cfg_priv)) {
+ brcmf_update_prof(cfg_priv, NULL, (void *)e->addr,
+ WL_PROF_BSSID);
+ wl_inform_ibss(cfg_priv, ndev, e->addr);
+ cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL);
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ set_bit(WL_STATUS_CONNECTED, &cfg_priv->status);
+ } else
+ brcmf_bss_connect_done(cfg_priv, ndev, e, true);
+ } else if (brcmf_is_linkdown(cfg_priv, e)) {
+ WL_CONN("Linkdown\n");
+ brcmf_link_down(cfg_priv);
+ brcmf_init_prof(cfg_priv->profile);
+ } else if (brcmf_is_nonetwork(cfg_priv, e)) {
+ if (brcmf_is_ibssmode(cfg_priv))
+ clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status);
+ else
+ brcmf_bss_connect_done(cfg_priv, ndev, e, false);
+ }
+
+ return err;
+}
+
+static s32
+brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv,
+ struct net_device *ndev,
+ const struct brcmf_event_msg *e, void *data)
+{
+ s32 err = 0;
+ u32 event = be32_to_cpu(e->event_type);
+ u32 status = be32_to_cpu(e->status);
+
+ if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
+ if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status))
+ brcmf_bss_roaming_done(cfg_priv, ndev, e);
+ else
+ brcmf_bss_connect_done(cfg_priv, ndev, e, true);
+ }
+
+ return err;
+}
+
+static s32
brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
@@ -2941,7 +3103,6 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv,
u16 flags = be16_to_cpu(e->flags);
enum nl80211_key_type key_type;
- rtnl_lock();
if (flags & BRCMF_EVENT_MSG_GROUP)
key_type = NL80211_KEYTYPE_GROUP;
else
@@ -2949,7 +3110,6 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv,
cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
NULL, GFP_KERNEL);
- rtnl_unlock();
return 0;
}
@@ -2959,11 +3119,12 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv,
struct net_device *ndev,
const struct brcmf_event_msg *e, void *data)
{
- struct brcmf_channel_info channel_inform;
- struct brcmf_scan_results *bss_list;
+ struct brcmf_channel_info_le channel_inform_le;
+ struct brcmf_scan_results_le *bss_list_le;
u32 len = WL_SCAN_BUF_MAX;
s32 err = 0;
bool scan_abort = false;
+ u32 scan_channel;
WL_TRACE("Enter\n");
@@ -2972,42 +3133,39 @@ brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv,
return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv));
}
- if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING,
- &cfg_priv->status))) {
+ if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) {
WL_ERR("Scan complete while device not scanning\n");
scan_abort = true;
err = -EINVAL;
goto scan_done_out;
}
- err = brcmf_dev_ioctl(ndev, BRCMF_C_GET_CHANNEL, &channel_inform,
- sizeof(channel_inform));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le,
+ sizeof(channel_inform_le));
+ if (err) {
WL_ERR("scan busy (%d)\n", err);
scan_abort = true;
goto scan_done_out;
}
- channel_inform.scan_channel = le32_to_cpu(channel_inform.scan_channel);
- if (unlikely(channel_inform.scan_channel)) {
-
- WL_CONN("channel_inform.scan_channel (%d)\n",
- channel_inform.scan_channel);
- }
+ scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
+ if (scan_channel)
+ WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
cfg_priv->bss_list = cfg_priv->scan_results;
- bss_list = cfg_priv->bss_list;
- memset(bss_list, 0, len);
- bss_list->buflen = cpu_to_le32(len);
+ bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list;
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SCAN_RESULTS, bss_list, len);
- if (unlikely(err)) {
+ memset(cfg_priv->scan_results, 0, len);
+ bss_list_le->buflen = cpu_to_le32(len);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS,
+ cfg_priv->scan_results, len);
+ if (err) {
WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
err = -EINVAL;
scan_abort = true;
goto scan_done_out;
}
- bss_list->buflen = le32_to_cpu(bss_list->buflen);
- bss_list->version = le32_to_cpu(bss_list->version);
- bss_list->count = le32_to_cpu(bss_list->count);
+ cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
+ cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version);
+ cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count);
err = brcmf_inform_bss(cfg_priv);
if (err) {
@@ -3038,11 +3196,6 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
conf->tx_power = -1;
}
-static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
-{
- memset(prof, 0, sizeof(*prof));
-}
-
static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
{
memset(el, 0, sizeof(*el));
@@ -3053,54 +3206,58 @@ static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
}
+static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ kfree(cfg_priv->scan_results);
+ cfg_priv->scan_results = NULL;
+ kfree(cfg_priv->bss_info);
+ cfg_priv->bss_info = NULL;
+ kfree(cfg_priv->conf);
+ cfg_priv->conf = NULL;
+ kfree(cfg_priv->profile);
+ cfg_priv->profile = NULL;
+ kfree(cfg_priv->scan_req_int);
+ cfg_priv->scan_req_int = NULL;
+ kfree(cfg_priv->dcmd_buf);
+ cfg_priv->dcmd_buf = NULL;
+ kfree(cfg_priv->extra_buf);
+ cfg_priv->extra_buf = NULL;
+ kfree(cfg_priv->iscan);
+ cfg_priv->iscan = NULL;
+ kfree(cfg_priv->pmk_list);
+ cfg_priv->pmk_list = NULL;
+}
+
static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
{
cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
- if (unlikely(!cfg_priv->scan_results)) {
- WL_ERR("Scan results alloc failed\n");
+ if (!cfg_priv->scan_results)
goto init_priv_mem_out;
- }
cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL);
- if (unlikely(!cfg_priv->conf)) {
- WL_ERR("wl_conf alloc failed\n");
+ if (!cfg_priv->conf)
goto init_priv_mem_out;
- }
cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL);
- if (unlikely(!cfg_priv->profile)) {
- WL_ERR("wl_profile alloc failed\n");
+ if (!cfg_priv->profile)
goto init_priv_mem_out;
- }
cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
- if (unlikely(!cfg_priv->bss_info)) {
- WL_ERR("Bss information alloc failed\n");
+ if (!cfg_priv->bss_info)
goto init_priv_mem_out;
- }
cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int),
GFP_KERNEL);
- if (unlikely(!cfg_priv->scan_req_int)) {
- WL_ERR("Scan req alloc failed\n");
+ if (!cfg_priv->scan_req_int)
goto init_priv_mem_out;
- }
- cfg_priv->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
- if (unlikely(!cfg_priv->ioctl_buf)) {
- WL_ERR("Ioctl buf alloc failed\n");
+ cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
+ if (!cfg_priv->dcmd_buf)
goto init_priv_mem_out;
- }
cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
- if (unlikely(!cfg_priv->extra_buf)) {
- WL_ERR("Extra buf alloc failed\n");
+ if (!cfg_priv->extra_buf)
goto init_priv_mem_out;
- }
cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL);
- if (unlikely(!cfg_priv->iscan)) {
- WL_ERR("Iscan buf alloc failed\n");
+ if (!cfg_priv->iscan)
goto init_priv_mem_out;
- }
cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL);
- if (unlikely(!cfg_priv->pmk_list)) {
- WL_ERR("pmk list alloc failed\n");
+ if (!cfg_priv->pmk_list)
goto init_priv_mem_out;
- }
return 0;
@@ -3110,301 +3267,111 @@ init_priv_mem_out:
return -ENOMEM;
}
-static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv)
-{
- kfree(cfg_priv->scan_results);
- cfg_priv->scan_results = NULL;
- kfree(cfg_priv->bss_info);
- cfg_priv->bss_info = NULL;
- kfree(cfg_priv->conf);
- cfg_priv->conf = NULL;
- kfree(cfg_priv->profile);
- cfg_priv->profile = NULL;
- kfree(cfg_priv->scan_req_int);
- cfg_priv->scan_req_int = NULL;
- kfree(cfg_priv->ioctl_buf);
- cfg_priv->ioctl_buf = NULL;
- kfree(cfg_priv->extra_buf);
- cfg_priv->extra_buf = NULL;
- kfree(cfg_priv->iscan);
- cfg_priv->iscan = NULL;
- kfree(cfg_priv->pmk_list);
- cfg_priv->pmk_list = NULL;
-}
-
-static s32 brcmf_create_event_handler(struct brcmf_cfg80211_priv *cfg_priv)
-{
- sema_init(&cfg_priv->event_sync, 0);
- cfg_priv->event_tsk = kthread_run(brcmf_event_handler, cfg_priv,
- "wl_event_handler");
- if (IS_ERR(cfg_priv->event_tsk)) {
- cfg_priv->event_tsk = NULL;
- WL_ERR("failed to create event thread\n");
- return -ENOMEM;
- }
- return 0;
-}
-
-static void brcmf_destroy_event_handler(struct brcmf_cfg80211_priv *cfg_priv)
-{
- if (cfg_priv->event_tsk) {
- send_sig(SIGTERM, cfg_priv->event_tsk, 1);
- kthread_stop(cfg_priv->event_tsk);
- cfg_priv->event_tsk = NULL;
- }
-}
+/*
+* retrieve first queued event from head
+*/
-static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+static struct brcmf_cfg80211_event_q *brcmf_deq_event(
+ struct brcmf_cfg80211_priv *cfg_priv)
{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
+ struct brcmf_cfg80211_event_q *e = NULL;
- if (cfg_priv->iscan_on && iscan->tsk) {
- iscan->state = WL_ISCAN_STATE_IDLE;
- send_sig(SIGTERM, iscan->tsk, 1);
- kthread_stop(iscan->tsk);
- iscan->tsk = NULL;
+ spin_lock_irq(&cfg_priv->evt_q_lock);
+ if (!list_empty(&cfg_priv->evt_q_list)) {
+ e = list_first_entry(&cfg_priv->evt_q_list,
+ struct brcmf_cfg80211_event_q, evt_q_list);
+ list_del(&e->evt_q_list);
}
-}
-
-static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
- bool aborted)
-{
- struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
- struct net_device *ndev = cfg_to_ndev(cfg_priv);
+ spin_unlock_irq(&cfg_priv->evt_q_lock);
- if (unlikely(!test_and_clear_bit(WL_STATUS_SCANNING,
- &cfg_priv->status))) {
- WL_ERR("Scan complete while device not scanning\n");
- return;
- }
- if (likely(cfg_priv->scan_request)) {
- WL_SCAN("ISCAN Completed scan: %s\n",
- aborted ? "Aborted" : "Done");
- cfg80211_scan_done(cfg_priv->scan_request, aborted);
- brcmf_set_mpc(ndev, 1);
- cfg_priv->scan_request = NULL;
- }
- cfg_priv->iscan_kickstart = false;
+ return e;
}
-static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
-{
- if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) {
- WL_SCAN("wake up iscan\n");
- up(&iscan->sync);
- return 0;
- }
-
- return -EIO;
-}
+/*
+** push event to tail of the queue
+*/
static s32
-brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
- struct brcmf_scan_results **bss_list)
-{
- struct brcmf_iscan_results list;
- struct brcmf_scan_results *results;
- struct brcmf_iscan_results *list_buf;
- s32 err = 0;
-
- memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
- list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
- results = &list_buf->results;
- results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE;
- results->version = 0;
- results->count = 0;
-
- memset(&list, 0, sizeof(list));
- list.results.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX);
- err = brcmf_dev_iovar_getbuf(iscan->dev, "iscanresults", &list,
- BRCMF_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
- WL_ISCAN_BUF_MAX);
- if (unlikely(err)) {
- WL_ERR("error (%d)\n", err);
- return err;
- }
- results->buflen = le32_to_cpu(results->buflen);
- results->version = le32_to_cpu(results->version);
- results->count = le32_to_cpu(results->count);
- WL_SCAN("results->count = %d\n", results->count);
- WL_SCAN("results->buflen = %d\n", results->buflen);
- *status = le32_to_cpu(list_buf->status);
- *bss_list = results;
-
- return err;
-}
-
-static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
- s32 err = 0;
-
- iscan->state = WL_ISCAN_STATE_IDLE;
- rtnl_lock();
- brcmf_inform_bss(cfg_priv);
- brcmf_notify_iscan_complete(iscan, false);
- rtnl_unlock();
-
- return err;
-}
-
-static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
- s32 err = 0;
-
- /* Reschedule the timer */
- mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
- iscan->timer_on = 1;
-
- return err;
-}
-
-static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv)
+brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
+ const struct brcmf_event_msg *msg)
{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
+ struct brcmf_cfg80211_event_q *e;
s32 err = 0;
- rtnl_lock();
- brcmf_inform_bss(cfg_priv);
- brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
- rtnl_unlock();
- /* Reschedule the timer */
- mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
- iscan->timer_on = 1;
-
- return err;
-}
+ e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
+ if (!e)
+ return -ENOMEM;
-static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan;
- s32 err = 0;
+ e->etype = event;
+ memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
- iscan->state = WL_ISCAN_STATE_IDLE;
- rtnl_lock();
- brcmf_notify_iscan_complete(iscan, true);
- rtnl_unlock();
+ spin_lock_irq(&cfg_priv->evt_q_lock);
+ list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list);
+ spin_unlock_irq(&cfg_priv->evt_q_lock);
return err;
}
-static s32 brcmf_iscan_thread(void *data)
+static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
{
- struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
- struct brcmf_cfg80211_iscan_ctrl *iscan =
- (struct brcmf_cfg80211_iscan_ctrl *)data;
- struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan);
- struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
- u32 status;
- int err = 0;
-
- sched_setscheduler(current, SCHED_FIFO, &param);
- allow_signal(SIGTERM);
- status = BRCMF_SCAN_RESULTS_PARTIAL;
- while (likely(!down_interruptible(&iscan->sync))) {
- if (kthread_should_stop())
- break;
- if (iscan->timer_on) {
- del_timer_sync(&iscan->timer);
- iscan->timer_on = 0;
- }
- rtnl_lock();
- err = brcmf_get_iscan_results(iscan, &status,
- &cfg_priv->bss_list);
- if (unlikely(err)) {
- status = BRCMF_SCAN_RESULTS_ABORTED;
- WL_ERR("Abort iscan\n");
- }
- rtnl_unlock();
- el->handler[status](cfg_priv);
- }
- if (iscan->timer_on) {
- del_timer_sync(&iscan->timer);
- iscan->timer_on = 0;
- }
- WL_SCAN("ISCAN thread terminated\n");
-
- return 0;
+ kfree(e);
}
-static void brcmf_iscan_timer(unsigned long data)
+static void brcmf_cfg80211_event_handler(struct work_struct *work)
{
- struct brcmf_cfg80211_iscan_ctrl *iscan =
- (struct brcmf_cfg80211_iscan_ctrl *)data;
+ struct brcmf_cfg80211_priv *cfg_priv =
+ container_of(work, struct brcmf_cfg80211_priv,
+ event_work);
+ struct brcmf_cfg80211_event_q *e;
- if (iscan) {
- iscan->timer_on = 0;
- WL_SCAN("timer expired\n");
- brcmf_wakeup_iscan(iscan);
+ e = brcmf_deq_event(cfg_priv);
+ if (unlikely(!e)) {
+ WL_ERR("event queue empty...\n");
+ return;
}
-}
-static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
- int err = 0;
-
- if (cfg_priv->iscan_on && !iscan->tsk) {
- iscan->state = WL_ISCAN_STATE_IDLE;
- sema_init(&iscan->sync, 0);
- iscan->tsk = kthread_run(brcmf_iscan_thread, iscan, "wl_iscan");
- if (IS_ERR(iscan->tsk)) {
- WL_ERR("Could not create iscan thread\n");
- iscan->tsk = NULL;
- return -ENOMEM;
- }
- }
+ do {
+ WL_INFO("event type (%d)\n", e->etype);
+ if (cfg_priv->el.handler[e->etype])
+ cfg_priv->el.handler[e->etype](cfg_priv,
+ cfg_to_ndev(cfg_priv),
+ &e->emsg, e->edata);
+ else
+ WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
+ brcmf_put_event(e);
+ } while ((e = brcmf_deq_event(cfg_priv)));
- return err;
}
-static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
+static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv)
{
- memset(el, 0, sizeof(*el));
- el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
- el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
- el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
- el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
- el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
+ spin_lock_init(&cfg_priv->evt_q_lock);
+ INIT_LIST_HEAD(&cfg_priv->evt_q_list);
}
-static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv)
+static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv)
{
- struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv);
- int err = 0;
+ struct brcmf_cfg80211_event_q *e;
- if (cfg_priv->iscan_on) {
- iscan->dev = cfg_to_ndev(cfg_priv);
- iscan->state = WL_ISCAN_STATE_IDLE;
- brcmf_init_iscan_eloop(&iscan->el);
- iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
- init_timer(&iscan->timer);
- iscan->timer.data = (unsigned long) iscan;
- iscan->timer.function = brcmf_iscan_timer;
- sema_init(&iscan->sync, 0);
- iscan->tsk = kthread_run(brcmf_iscan_thread, iscan, "wl_iscan");
- if (IS_ERR(iscan->tsk)) {
- WL_ERR("Could not create iscan thread\n");
- iscan->tsk = NULL;
- return -ENOMEM;
- }
- iscan->data = cfg_priv;
+ spin_lock_irq(&cfg_priv->evt_q_lock);
+ while (!list_empty(&cfg_priv->evt_q_list)) {
+ e = list_first_entry(&cfg_priv->evt_q_list,
+ struct brcmf_cfg80211_event_q, evt_q_list);
+ list_del(&e->evt_q_list);
+ kfree(e);
}
-
- return err;
+ spin_unlock_irq(&cfg_priv->evt_q_lock);
}
static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
{
- struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
s32 err = 0;
cfg_priv->scan_request = NULL;
- cfg_priv->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
+ cfg_priv->pwr_save = true;
cfg_priv->iscan_on = true; /* iscan on & off switch.
we enable iscan per default */
- cfg_priv->roam_on = false; /* roam on & off switch.
+ cfg_priv->roam_on = true; /* roam on & off switch.
we enable roam per default */
cfg_priv->iscan_kickstart = false;
@@ -3413,14 +3380,13 @@ static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
cfg_priv->dongle_up = false; /* dongle is not up yet */
brcmf_init_eq(cfg_priv);
err = brcmf_init_priv_mem(cfg_priv);
- if (unlikely(err))
+ if (err)
return err;
- if (unlikely(brcmf_create_event_handler(cfg_priv)))
- return -ENOMEM;
+ INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler);
brcmf_init_eloop_handler(&cfg_priv->el);
mutex_init(&cfg_priv->usr_sync);
err = brcmf_init_iscan(cfg_priv);
- if (unlikely(err))
+ if (err)
return err;
brcmf_init_conf(cfg_priv->conf);
brcmf_init_prof(cfg_priv->profile);
@@ -3431,7 +3397,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv)
static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv)
{
- brcmf_destroy_event_handler(cfg_priv);
+ cancel_work_sync(&cfg_priv->event_work);
cfg_priv->dongle_up = false; /* dongle down */
brcmf_flush_eq(cfg_priv);
brcmf_link_down(cfg_priv);
@@ -3439,27 +3405,29 @@ static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv)
brcmf_deinit_priv_mem(cfg_priv);
}
-s32 brcmf_cfg80211_attach(struct net_device *ndev, void *data)
+struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
+ struct device *busdev,
+ void *data)
{
struct wireless_dev *wdev;
struct brcmf_cfg80211_priv *cfg_priv;
struct brcmf_cfg80211_iface *ci;
+ struct brcmf_cfg80211_dev *cfg_dev;
s32 err = 0;
- if (unlikely(!ndev)) {
+ if (!ndev) {
WL_ERR("ndev is invalid\n");
- return -ENODEV;
+ return NULL;
}
- cfg80211_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL);
- if (unlikely(!cfg80211_dev)) {
- WL_ERR("wl_cfg80211_dev is invalid\n");
- return -ENOMEM;
+ cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL);
+ if (!cfg_dev)
+ return NULL;
+
+ wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev);
+ if (IS_ERR(wdev)) {
+ kfree(cfg_dev);
+ return NULL;
}
- WL_INFO("func %p\n", brcmf_cfg80211_get_sdio_func());
- wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface),
- &brcmf_cfg80211_get_sdio_func()->dev);
- if (IS_ERR(wdev))
- return -ENOMEM;
wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS);
cfg_priv = wdev_to_cfg(wdev);
@@ -3471,67 +3439,30 @@ s32 brcmf_cfg80211_attach(struct net_device *ndev, void *data)
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
err = wl_init_priv(cfg_priv);
- if (unlikely(err)) {
+ if (err) {
WL_ERR("Failed to init iwm_priv (%d)\n", err);
goto cfg80211_attach_out;
}
- brcmf_set_drvdata(cfg80211_dev, ci);
+ brcmf_set_drvdata(cfg_dev, ci);
- return err;
+ return cfg_dev;
cfg80211_attach_out:
brcmf_free_wdev(cfg_priv);
- return err;
+ kfree(cfg_dev);
+ return NULL;
}
-void brcmf_cfg80211_detach(void)
+void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev)
{
struct brcmf_cfg80211_priv *cfg_priv;
- cfg_priv = WL_PRIV_GET();
+ cfg_priv = brcmf_priv_get(cfg_dev);
wl_deinit_priv(cfg_priv);
brcmf_free_wdev(cfg_priv);
- brcmf_set_drvdata(cfg80211_dev, NULL);
- kfree(cfg80211_dev);
- cfg80211_dev = NULL;
- brcmf_clear_sdio_func();
-}
-
-static void brcmf_wakeup_event(struct brcmf_cfg80211_priv *cfg_priv)
-{
- up(&cfg_priv->event_sync);
-}
-
-static s32 brcmf_event_handler(void *data)
-{
- struct brcmf_cfg80211_priv *cfg_priv =
- (struct brcmf_cfg80211_priv *)data;
- struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
- struct brcmf_cfg80211_event_q *e;
-
- sched_setscheduler(current, SCHED_FIFO, &param);
- allow_signal(SIGTERM);
- while (likely(!down_interruptible(&cfg_priv->event_sync))) {
- if (kthread_should_stop())
- break;
- e = brcmf_deq_event(cfg_priv);
- if (unlikely(!e)) {
- WL_ERR("event queue empty...\n");
- BUG();
- }
- WL_INFO("event type (%d)\n", e->etype);
- if (cfg_priv->el.handler[e->etype]) {
- cfg_priv->el.handler[e->etype](cfg_priv,
- cfg_to_ndev(cfg_priv),
- &e->emsg, e->edata);
- } else {
- WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
- }
- brcmf_put_event(e);
- }
- WL_INFO("was terminated\n");
- return 0;
+ brcmf_set_drvdata(cfg_dev, NULL);
+ kfree(cfg_dev);
}
void
@@ -3541,95 +3472,8 @@ brcmf_cfg80211_event(struct net_device *ndev,
u32 event_type = be32_to_cpu(e->event_type);
struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
- if (likely(!brcmf_enq_event(cfg_priv, event_type, e, data)))
- brcmf_wakeup_event(cfg_priv);
-}
-
-static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv)
-{
- brcmf_init_eq_lock(cfg_priv);
- INIT_LIST_HEAD(&cfg_priv->eq_list);
-}
-
-static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_event_q *e;
-
- brcmf_lock_eq(cfg_priv);
- while (!list_empty(&cfg_priv->eq_list)) {
- e = list_first_entry(&cfg_priv->eq_list,
- struct brcmf_cfg80211_event_q, eq_list);
- list_del(&e->eq_list);
- kfree(e);
- }
- brcmf_unlock_eq(cfg_priv);
-}
-
-/*
-* retrieve first queued event from head
-*/
-
-static struct brcmf_cfg80211_event_q *brcmf_deq_event(
- struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct brcmf_cfg80211_event_q *e = NULL;
-
- brcmf_lock_eq(cfg_priv);
- if (likely(!list_empty(&cfg_priv->eq_list))) {
- e = list_first_entry(&cfg_priv->eq_list,
- struct brcmf_cfg80211_event_q, eq_list);
- list_del(&e->eq_list);
- }
- brcmf_unlock_eq(cfg_priv);
-
- return e;
-}
-
-/*
-** push event to tail of the queue
-*/
-
-static s32
-brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event,
- const struct brcmf_event_msg *msg, void *data)
-{
- struct brcmf_cfg80211_event_q *e;
- s32 err = 0;
-
- e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL);
- if (unlikely(!e)) {
- WL_ERR("event alloc failed\n");
- return -ENOMEM;
- }
-
- e->etype = event;
- memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
-
- brcmf_lock_eq(cfg_priv);
- list_add_tail(&e->eq_list, &cfg_priv->eq_list);
- brcmf_unlock_eq(cfg_priv);
-
- return err;
-}
-
-static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
-{
- kfree(e);
-}
-
-void brcmf_cfg80211_sdio_func(void *func)
-{
- cfg80211_sdio_func = (struct sdio_func *)func;
-}
-
-static void brcmf_clear_sdio_func(void)
-{
- cfg80211_sdio_func = NULL;
-}
-
-struct sdio_func *brcmf_cfg80211_get_sdio_func(void)
-{
- return cfg80211_sdio_func;
+ if (!brcmf_enq_event(cfg_priv, event_type, e))
+ schedule_work(&cfg_priv->event_work);
}
static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
@@ -3655,9 +3499,8 @@ static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
WL_ERR("invalid type (%d)\n", iftype);
return err;
}
- infra = cpu_to_le32(infra);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_INFRA, &infra, sizeof(infra));
- if (unlikely(err)) {
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
+ if (err) {
WL_ERR("WLC_SET_INFRA error (%d)\n", err);
return err;
}
@@ -3675,10 +3518,10 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
WL_TRACE("Enter\n");
/* Setup event_msgs */
- brcmu_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf,
- sizeof(iovbuf));
- err = brcmf_dev_ioctl(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
+ brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf));
+ if (err) {
WL_ERR("Get event_msgs error (%d)\n", err);
goto dongle_eventmsg_out;
}
@@ -3704,10 +3547,10 @@ static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
setbit(eventmask, BRCMF_E_JOIN_START);
setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
- brcmu_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, iovbuf,
- sizeof(iovbuf));
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
+ brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN,
+ iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (err) {
WL_ERR("Set event_msgs error (%d)\n", err);
goto dongle_eventmsg_out;
}
@@ -3721,20 +3564,23 @@ static s32
brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
{
s8 iovbuf[32];
- s32 roamtrigger[2];
- s32 roam_delta[2];
s32 err = 0;
+ __le32 roamtrigger[2];
+ __le32 roam_delta[2];
+ __le32 bcn_to_le;
+ __le32 roamvar_le;
/*
* Setup timeout if Beacons are lost and roam is
* off to report link down
*/
if (roamvar) {
- brcmu_mkiovar("bcn_timeout", (char *)&bcn_timeout,
- sizeof(bcn_timeout), iovbuf, sizeof(iovbuf));
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_VAR,
+ bcn_to_le = cpu_to_le32(bcn_timeout);
+ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le,
+ sizeof(bcn_to_le), iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR,
iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
+ if (err) {
WL_ERR("bcn_timeout error (%d)\n", err);
goto dongle_rom_out;
}
@@ -3745,28 +3591,29 @@ brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
* to take care of roaming
*/
WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On");
- brcmu_mkiovar("roam_off", (char *)&roamvar,
- sizeof(roamvar), iovbuf, sizeof(iovbuf));
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
- if (unlikely(err)) {
+ roamvar_le = cpu_to_le32(roamvar);
+ brcmf_c_mkiovar("roam_off", (char *)&roamvar_le,
+ sizeof(roamvar_le), iovbuf, sizeof(iovbuf));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf));
+ if (err) {
WL_ERR("roam_off error (%d)\n", err);
goto dongle_rom_out;
}
- roamtrigger[0] = WL_ROAM_TRIGGER_LEVEL;
- roamtrigger[1] = BRCM_BAND_ALL;
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_ROAM_TRIGGER,
+ roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL);
+ roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER,
(void *)roamtrigger, sizeof(roamtrigger));
- if (unlikely(err)) {
+ if (err) {
WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err);
goto dongle_rom_out;
}
- roam_delta[0] = WL_ROAM_DELTA;
- roam_delta[1] = BRCM_BAND_ALL;
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_ROAM_DELTA,
+ roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
+ roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA,
(void *)roam_delta, sizeof(roam_delta));
- if (unlikely(err)) {
+ if (err) {
WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err);
goto dongle_rom_out;
}
@@ -3777,12 +3624,15 @@ dongle_rom_out:
static s32
brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
- s32 scan_unassoc_time, s32 scan_passive_time)
+ s32 scan_unassoc_time, s32 scan_passive_time)
{
s32 err = 0;
+ __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time);
+ __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time);
+ __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time);
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
- &scan_assoc_time, sizeof(scan_assoc_time));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME,
+ &scan_assoc_tm_le, sizeof(scan_assoc_tm_le));
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO("Scan assoc time is not supported\n");
@@ -3790,8 +3640,8 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
WL_ERR("Scan assoc time error (%d)\n", err);
goto dongle_scantime_out;
}
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
- &scan_unassoc_time, sizeof(scan_unassoc_time));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME,
+ &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le));
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO("Scan unassoc time is not supported\n");
@@ -3800,8 +3650,8 @@ brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
goto dongle_scantime_out;
}
- err = brcmf_dev_ioctl(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
- &scan_passive_time, sizeof(scan_passive_time));
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME,
+ &scan_passive_tm_le, sizeof(scan_passive_tm_le));
if (err) {
if (err == -EOPNOTSUPP)
WL_INFO("Scan passive time is not supported\n");
@@ -3814,10 +3664,40 @@ dongle_scantime_out:
return err;
}
-s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, bool need_lock)
+static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ struct wiphy *wiphy;
+ s32 phy_list;
+ s8 phy;
+ s32 err = 0;
+
+ err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST,
+ &phy_list, sizeof(phy_list));
+ if (err) {
+ WL_ERR("error (%d)\n", err);
+ return err;
+ }
+
+ phy = ((char *)&phy_list)[1];
+ WL_INFO("%c phy\n", phy);
+ if (phy == 'n' || phy == 'a') {
+ wiphy = cfg_to_wiphy(cfg_priv);
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ }
+
+ return err;
+}
+
+static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ return wl_update_wiphybands(cfg_priv);
+}
+
+static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv)
{
struct net_device *ndev;
struct wireless_dev *wdev;
+ s32 power_mode;
s32 err = 0;
if (cfg_priv->dongle_up)
@@ -3825,31 +3705,35 @@ s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv, bool need_lock)
ndev = cfg_to_ndev(cfg_priv);
wdev = ndev->ieee80211_ptr;
- if (need_lock)
- rtnl_lock();
brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
err = brcmf_dongle_eventmsg(ndev);
- if (unlikely(err))
+ if (err)
goto default_conf_out;
+
+ power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF;
+ err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode);
+ if (err)
+ goto default_conf_out;
+ WL_INFO("power save set to %s\n",
+ (power_mode ? "enabled" : "disabled"));
+
err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1),
WL_BEACON_TIMEOUT);
- if (unlikely(err))
+ if (err)
goto default_conf_out;
err = brcmf_dongle_mode(ndev, wdev->iftype);
- if (unlikely(err && err != -EINPROGRESS))
+ if (err && err != -EINPROGRESS)
goto default_conf_out;
err = brcmf_dongle_probecap(cfg_priv);
- if (unlikely(err))
+ if (err)
goto default_conf_out;
/* -EINPROGRESS: Call commit handler */
default_conf_out:
- if (need_lock)
- rtnl_unlock();
cfg_priv->dongle_up = true;
@@ -3857,30 +3741,40 @@ default_conf_out:
}
-static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv)
+static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv)
{
- struct wiphy *wiphy;
- s32 phy_list;
- s8 phy;
+ char buf[10+IFNAMSIZ];
+ struct dentry *fd;
s32 err = 0;
- err = brcmf_dev_ioctl(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST,
- &phy_list, sizeof(phy_list));
- if (unlikely(err)) {
- WL_ERR("error (%d)\n", err);
- return err;
+ sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name);
+ cfg_priv->debugfsdir = debugfs_create_dir(buf,
+ cfg_to_wiphy(cfg_priv)->debugfsdir);
+
+ fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir,
+ (u16 *)&cfg_priv->profile->beacon_interval);
+ if (!fd) {
+ err = -ENOMEM;
+ goto err_out;
}
- phy = ((char *)&phy_list)[1];
- WL_INFO("%c phy\n", phy);
- if (phy == 'n' || phy == 'a') {
- wiphy = cfg_to_wiphy(cfg_priv);
- wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n;
+ fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir,
+ (u8 *)&cfg_priv->profile->dtim_period);
+ if (!fd) {
+ err = -ENOMEM;
+ goto err_out;
}
+err_out:
return err;
}
+static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv)
+{
+ debugfs_remove_recursive(cfg_priv->debugfsdir);
+ cfg_priv->debugfsdir = NULL;
+}
+
static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv)
{
s32 err = 0;
@@ -3889,8 +3783,8 @@ static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv)
brcmf_debugfs_add_netdev_params(cfg_priv);
- err = brcmf_config_dongle(cfg_priv, false);
- if (unlikely(err))
+ err = brcmf_config_dongle(cfg_priv);
+ if (err)
return err;
brcmf_invoke_iscan(cfg_priv);
@@ -3914,9 +3808,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv)
generated due to DISASSOC call to the fw to keep
the state fw and WPA_Supplicant state consistent
*/
- rtnl_unlock();
brcmf_delay(500);
- rtnl_lock();
}
set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
@@ -3931,17 +3823,18 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv)
clear_bit(WL_STATUS_SCANNING, &cfg_priv->status);
clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status);
+ brcmf_link_down(cfg_priv);
brcmf_debugfs_remove_netdev(cfg_priv);
return 0;
}
-s32 brcmf_cfg80211_up(void)
+s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev)
{
struct brcmf_cfg80211_priv *cfg_priv;
s32 err = 0;
- cfg_priv = WL_PRIV_GET();
+ cfg_priv = brcmf_priv_get(cfg_dev);
mutex_lock(&cfg_priv->usr_sync);
err = __brcmf_cfg80211_up(cfg_priv);
mutex_unlock(&cfg_priv->usr_sync);
@@ -3949,12 +3842,12 @@ s32 brcmf_cfg80211_up(void)
return err;
}
-s32 brcmf_cfg80211_down(void)
+s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev)
{
struct brcmf_cfg80211_priv *cfg_priv;
s32 err = 0;
- cfg_priv = WL_PRIV_GET();
+ cfg_priv = brcmf_priv_get(cfg_dev);
mutex_lock(&cfg_priv->usr_sync);
err = __brcmf_cfg80211_down(cfg_priv);
mutex_unlock(&cfg_priv->usr_sync);
@@ -3962,78 +3855,13 @@ s32 brcmf_cfg80211_down(void)
return err;
}
-static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv)
-{
- return wl_update_wiphybands(cfg_priv);
-}
-
-static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item)
-{
- switch (item) {
- case WL_PROF_SEC:
- return &cfg_priv->profile->sec;
- case WL_PROF_BSSID:
- return &cfg_priv->profile->bssid;
- case WL_PROF_SSID:
- return &cfg_priv->profile->ssid;
- }
- WL_ERR("invalid item (%d)\n", item);
- return NULL;
-}
-
-static s32
-brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv,
- const struct brcmf_event_msg *e, void *data, s32 item)
-{
- s32 err = 0;
- struct brcmf_ssid *ssid;
-
- switch (item) {
- case WL_PROF_SSID:
- ssid = (struct brcmf_ssid *) data;
- memset(cfg_priv->profile->ssid.SSID, 0,
- sizeof(cfg_priv->profile->ssid.SSID));
- memcpy(cfg_priv->profile->ssid.SSID,
- ssid->SSID, ssid->SSID_len);
- cfg_priv->profile->ssid.SSID_len = ssid->SSID_len;
- break;
- case WL_PROF_BSSID:
- if (data)
- memcpy(cfg_priv->profile->bssid, data, ETH_ALEN);
- else
- memset(cfg_priv->profile->bssid, 0, ETH_ALEN);
- break;
- case WL_PROF_SEC:
- memcpy(&cfg_priv->profile->sec, data,
- sizeof(cfg_priv->profile->sec));
- break;
- case WL_PROF_BEACONINT:
- cfg_priv->profile->beacon_interval = *(u16 *)data;
- break;
- case WL_PROF_DTIMPERIOD:
- cfg_priv->profile->dtim_period = *(u8 *)data;
- break;
- default:
- WL_ERR("unsupported item (%d)\n", item);
- err = -EOPNOTSUPP;
- break;
- }
-
- return err;
-}
-
-static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv)
-{
- return cfg_priv->conf->mode == WL_MODE_IBSS;
-}
-
static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
u8 t, u8 l, u8 *v)
{
struct brcmf_cfg80211_ie *ie = &cfg_priv->ie;
s32 err = 0;
- if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
+ if (ie->offset + l + 2 > WL_TLV_INFO_MAX) {
WL_ERR("ei crosses buffer boundary\n");
return -ENOSPC;
}
@@ -4044,109 +3872,3 @@ static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv,
return err;
}
-
-static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv)
-{
- struct net_device *dev = NULL;
- s32 err = 0;
-
- WL_TRACE("Enter\n");
-
- if (cfg_priv->link_up) {
- dev = cfg_to_ndev(cfg_priv);
- WL_INFO("Call WLC_DISASSOC to stop excess roaming\n ");
- err = brcmf_dev_ioctl(dev, BRCMF_C_DISASSOC, NULL, 0);
- if (unlikely(err))
- WL_ERR("WLC_DISASSOC failed (%d)\n", err);
- cfg_priv->link_up = false;
- }
- WL_TRACE("Exit\n");
-}
-
-static void brcmf_lock_eq(struct brcmf_cfg80211_priv *cfg_priv)
-{
- spin_lock_irq(&cfg_priv->eq_lock);
-}
-
-static void brcmf_unlock_eq(struct brcmf_cfg80211_priv *cfg_priv)
-{
- spin_unlock_irq(&cfg_priv->eq_lock);
-}
-
-static void brcmf_init_eq_lock(struct brcmf_cfg80211_priv *cfg_priv)
-{
- spin_lock_init(&cfg_priv->eq_lock);
-}
-
-static void brcmf_delay(u32 ms)
-{
- if (ms < 1000 / HZ) {
- cond_resched();
- mdelay(ms);
- } else {
- msleep(ms);
- }
-}
-
-static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data)
-{
- dev->driver_data = data;
-}
-
-static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev)
-{
- void *data = NULL;
-
- if (dev)
- data = dev->driver_data;
- return data;
-}
-
-static void brcmf_set_mpc(struct net_device *ndev, int mpc)
-{
- s32 err = 0;
- struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev);
-
- if (test_bit(WL_STATUS_READY, &cfg_priv->status)) {
- err = brcmf_dev_intvar_set(ndev, "mpc", mpc);
- if (unlikely(err)) {
- WL_ERR("fail to set mpc\n");
- return;
- }
- WL_INFO("MPC : %d\n", mpc);
- }
-}
-
-static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv)
-{
- char buf[10+IFNAMSIZ];
- struct dentry *fd;
- s32 err = 0;
-
- sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name);
- cfg_priv->debugfsdir = debugfs_create_dir(buf,
- cfg_to_wiphy(cfg_priv)->debugfsdir);
-
- fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir,
- (u16 *)&cfg_priv->profile->beacon_interval);
- if (!fd) {
- err = -ENOMEM;
- goto err_out;
- }
-
- fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir,
- (u8 *)&cfg_priv->profile->dtim_period);
- if (!fd) {
- err = -ENOMEM;
- goto err_out;
- }
-
-err_out:
- return err;
-}
-
-static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv)
-{
- debugfs_remove_recursive(cfg_priv->debugfsdir);
- cfg_priv->debugfsdir = NULL;
-}
diff --git a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
index f26d08793ca8..62dc46144ede 100644
--- a/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
+++ b/drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h
@@ -103,10 +103,10 @@ do { \
* report it to cfg80211 through "connect"
* event
*/
-#define WL_IOCTL_LEN_MAX 1024
+#define WL_DCMD_LEN_MAX 1024
#define WL_EXTRA_BUF_MAX 2048
#define WL_ISCAN_BUF_MAX 2048 /*
- * the buf length can be BRCMF_C_IOCTL_MAXLEN
+ * the buf length can be BRCMF_DCMD_MAXLEN
* to reduce iteration
*/
#define WL_ISCAN_TIMER_INTERVAL_MS 3000
@@ -188,7 +188,7 @@ struct brcmf_cfg80211_dev {
/* basic structure of scan request */
struct brcmf_cfg80211_scan_req {
- struct brcmf_ssid ssid;
+ struct brcmf_ssid_le ssid_le;
};
/* basic structure of information element */
@@ -199,7 +199,7 @@ struct brcmf_cfg80211_ie {
/* event queue for cfg80211 main event */
struct brcmf_cfg80211_event_q {
- struct list_head eq_list;
+ struct list_head evt_q_list;
u32 etype;
struct brcmf_event_msg emsg;
s8 edata[1];
@@ -243,16 +243,15 @@ struct brcmf_cfg80211_iscan_eloop {
/* dongle iscan controller */
struct brcmf_cfg80211_iscan_ctrl {
- struct net_device *dev;
+ struct net_device *ndev;
struct timer_list timer;
u32 timer_ms;
u32 timer_on;
s32 state;
- struct task_struct *tsk;
- struct semaphore sync;
+ struct work_struct work;
struct brcmf_cfg80211_iscan_eloop el;
void *data;
- s8 ioctl_buf[BRCMF_C_IOCTL_SMLEN];
+ s8 dcmd_buf[BRCMF_DCMD_SMLEN];
s8 scan_buf[WL_ISCAN_BUF_MAX];
};
@@ -265,15 +264,15 @@ struct brcmf_cfg80211_connect_info {
};
/* assoc ie length */
-struct brcmf_cfg80211_assoc_ielen {
- u32 req_len;
- u32 resp_len;
+struct brcmf_cfg80211_assoc_ielen_le {
+ __le32 req_len;
+ __le32 resp_len;
};
/* wpa2 pmk list */
struct brcmf_cfg80211_pmk_list {
- pmkid_list_t pmkids;
- pmkid_t foo[MAXPMKID - 1];
+ struct pmkid_list pmkids;
+ struct pmkid foo[MAXPMKID - 1];
};
/* dongle private data of cfg80211 interface */
@@ -283,8 +282,8 @@ struct brcmf_cfg80211_priv {
struct cfg80211_scan_request *scan_request; /* scan request
object */
struct brcmf_cfg80211_event_loop el; /* main event loop */
- struct list_head eq_list; /* used for event queue */
- spinlock_t eq_lock; /* for event queue synchronization */
+ struct list_head evt_q_list; /* used for event queue */
+ spinlock_t evt_q_lock; /* for event queue synchronization */
struct mutex usr_sync; /* maily for dongle up/down synchronization */
struct brcmf_scan_results *bss_list; /* bss_list holding scanned
ap information */
@@ -295,13 +294,11 @@ struct brcmf_cfg80211_priv {
cfg80211 layer */
struct brcmf_cfg80211_ie ie; /* information element object for
internal purpose */
- struct semaphore event_sync; /* for synchronization of main event
- thread */
struct brcmf_cfg80211_profile *profile; /* holding dongle profile */
struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */
struct brcmf_cfg80211_connect_info conn_info; /* association info */
struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */
- struct task_struct *event_tsk; /* task of main event handler thread */
+ struct work_struct event_work; /* event handler work struct */
unsigned long status; /* current dongle status */
void *pub;
u32 channel; /* current channel */
@@ -315,21 +312,45 @@ struct brcmf_cfg80211_priv {
bool dongle_up; /* indicate whether dongle up or not */
bool roam_on; /* on/off switch for dongle self-roaming */
bool scan_tried; /* indicates if first scan attempted */
- u8 *ioctl_buf; /* ioctl buffer */
- u8 *extra_buf; /* maily to grab assoc information */
+ u8 *dcmd_buf; /* dcmd buffer */
+ u8 *extra_buf; /* maily to grab assoc information */
struct dentry *debugfsdir;
- u8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN)));
+ u8 ci[0] __aligned(NETDEV_ALIGN);
};
-#define cfg_to_wiphy(w) (w->wdev->wiphy)
-#define wiphy_to_cfg(w) ((struct brcmf_cfg80211_priv *)(wiphy_priv(w)))
-#define cfg_to_wdev(w) (w->wdev)
-#define wdev_to_cfg(w) ((struct brcmf_cfg80211_priv *)(wdev_priv(w)))
-#define cfg_to_ndev(w) (w->wdev->netdev)
-#define ndev_to_cfg(n) (wdev_to_cfg(n->ieee80211_ptr))
+static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w)
+{
+ return w->wdev->wiphy;
+}
+
+static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w)
+{
+ return (struct brcmf_cfg80211_priv *)(wiphy_priv(w));
+}
+
+static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd)
+{
+ return (struct brcmf_cfg80211_priv *)(wdev_priv(wd));
+}
+
+static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg)
+{
+ return cfg->wdev->netdev;
+}
+
+static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev)
+{
+ return wdev_to_cfg(ndev->ieee80211_ptr);
+}
+
#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data))
#define cfg_to_iscan(w) (w->iscan)
-#define cfg_to_conn(w) (&w->conn_info)
+
+static inline struct
+brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
+{
+ return &cfg->conn_info;
+}
static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list,
struct brcmf_bss_info *bss)
@@ -340,17 +361,15 @@ static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list,
list->bss_info;
}
-#define for_each_bss(list, bss, __i) \
- for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
+extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
+ struct device *busdev,
+ void *data);
+extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg);
-extern s32 brcmf_cfg80211_attach(struct net_device *ndev, void *data);
-extern void brcmf_cfg80211_detach(void);
/* event handler from dongle */
extern void brcmf_cfg80211_event(struct net_device *ndev,
const struct brcmf_event_msg *e, void *data);
-extern void brcmf_cfg80211_sdio_func(void *func); /* set sdio function info */
-extern struct sdio_func *brcmf_cfg80211_get_sdio_func(void);
-extern s32 brcmf_cfg80211_up(void); /* dongle up */
-extern s32 brcmf_cfg80211_down(void); /* dongle down */
+extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev);
+extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev);
#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/Makefile b/drivers/staging/brcm80211/brcmsmac/Makefile
index 1ea3e0c48f3e..c2eb2d0af386 100644
--- a/drivers/staging/brcm80211/brcmsmac/Makefile
+++ b/drivers/staging/brcm80211/brcmsmac/Makefile
@@ -15,25 +15,17 @@
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-ccflags-y := \
- -DWLC_HIGH \
- -DWLC_LOW \
- -DSTA \
- -DWME \
- -DWL11N \
- -DDBAND \
- -DBCMNVRAMR \
- -Idrivers/staging/brcm80211/brcmsmac \
- -Idrivers/staging/brcm80211/brcmsmac/phy \
- -Idrivers/staging/brcm80211/include
+ccflags-y := \
+ -D__CHECK_ENDIAN__ \
+ -Idrivers/net/wireless/brcm80211/brcmsmac \
+ -Idrivers/net/wireless/brcm80211/brcmsmac/phy \
+ -Idrivers/net/wireless/brcm80211/include
BRCMSMAC_OFILES := \
mac80211_if.o \
ucode_loader.o \
- alloc.o \
ampdu.o \
antsel.o \
- bmac.o \
channel.o \
main.o \
phy_shim.o \
@@ -50,7 +42,8 @@ BRCMSMAC_OFILES := \
otp.o \
srom.o \
dma.o \
- nicpci.o
+ nicpci.o \
+ brcms_trace_events.o
MODULEPFX := brcmsmac
diff --git a/drivers/staging/brcm80211/brcmsmac/aiutils.c b/drivers/staging/brcm80211/brcmsmac/aiutils.c
index a25901e9981b..025fa0eb6f47 100644
--- a/drivers/staging/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/staging/brcm80211/brcmsmac/aiutils.c
@@ -12,7 +12,10 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * File contents: support functions for PCI/PCIe
*/
+
#include <linux/delay.h>
#include <linux/pci.h>
@@ -20,6 +23,7 @@
#include <chipcommon.h>
#include <brcmu_utils.h>
#include <brcm_hw_ids.h>
+#include <soc.h>
#include "types.h"
#include "pub.h"
#include "pmu.h"
@@ -28,48 +32,68 @@
#include "aiutils.h"
/* slow_clk_ctl */
-#define SCC_SS_MASK 0x00000007 /* slow clock source mask */
-#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */
-#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */
-#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */
-#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
-#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled,
- * 0: LPO is enabled
- */
-#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock,
- * 0: power logic control
- */
-#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors
- * PLL clock disable requests from core
- */
-#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't
- * disable crystal when appropriate
- */
-#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
-#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */
+ /* slow clock source mask */
+#define SCC_SS_MASK 0x00000007
+ /* source of slow clock is LPO */
+#define SCC_SS_LPO 0x00000000
+ /* source of slow clock is crystal */
+#define SCC_SS_XTAL 0x00000001
+ /* source of slow clock is PCI */
+#define SCC_SS_PCI 0x00000002
+ /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
+#define SCC_LF 0x00000200
+ /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
+#define SCC_LP 0x00000400
+ /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
+#define SCC_FS 0x00000800
+ /* IgnorePllOffReq, 1/0:
+ * power logic ignores/honors PLL clock disable requests from core
+ */
+#define SCC_IP 0x00001000
+ /* XtalControlEn, 1/0:
+ * power logic does/doesn't disable crystal when appropriate
+ */
+#define SCC_XC 0x00002000
+ /* XtalPU (RO), 1/0: crystal running/disabled */
+#define SCC_XP 0x00004000
+ /* ClockDivider (SlowClk = 1/(4+divisor)) */
+#define SCC_CD_MASK 0xffff0000
#define SCC_CD_SHIFT 16
/* system_clk_ctl */
-#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */
-#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */
-#define SYCC_FP 0x00000004 /* ForcePLLOn */
-#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */
-#define SYCC_HR 0x00000010 /* Force HT */
-#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */
+ /* ILPen: Enable Idle Low Power */
+#define SYCC_IE 0x00000001
+ /* ALPen: Enable Active Low Power */
+#define SYCC_AE 0x00000002
+ /* ForcePLLOn */
+#define SYCC_FP 0x00000004
+ /* Force ALP (or HT if ALPen is not set */
+#define SYCC_AR 0x00000008
+ /* Force HT */
+#define SYCC_HR 0x00000010
+ /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */
+#define SYCC_CD_MASK 0xffff0000
#define SYCC_CD_SHIFT 16
#define CST4329_SPROM_OTP_SEL_MASK 0x00000003
-#define CST4329_DEFCIS_SEL 0 /* OTP is powered up, use def. CIS, no SPROM */
-#define CST4329_SPROM_SEL 1 /* OTP is powered up, SPROM is present */
-#define CST4329_OTP_SEL 2 /* OTP is powered up, no SPROM */
-#define CST4329_OTP_PWRDN 3 /* OTP is powered down, SPROM is present */
+ /* OTP is powered up, use def. CIS, no SPROM */
+#define CST4329_DEFCIS_SEL 0
+ /* OTP is powered up, SPROM is present */
+#define CST4329_SPROM_SEL 1
+ /* OTP is powered up, no SPROM */
+#define CST4329_OTP_SEL 2
+ /* OTP is powered down, SPROM is present */
+#define CST4329_OTP_PWRDN 3
+
#define CST4329_SPI_SDIO_MODE_MASK 0x00000004
#define CST4329_SPI_SDIO_MODE_SHIFT 2
/* 43224 chip-specific ChipControl register bits */
#define CCTRL43224_GPIO_TOGGLE 0x8000
-#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */
-#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */
+ /* 12 mA drive strength */
+#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0
+ /* 12 mA drive strength for later 43224s */
+#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0
/* 43236 Chip specific ChipStatus register bits */
#define CST43236_SFLASH_MASK 0x00000040
@@ -78,29 +102,44 @@
#define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */
#define CST43236_BOOT_MASK 0x00001800
#define CST43236_BOOT_SHIFT 11
-#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */
-#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */
-#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */
+#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */
+#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */
+#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */
#define CST43236_BOOT_FROM_INVALID 3
/* 4331 chip-specific ChipControl register bits */
-#define CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */
-#define CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */
-#define CCTRL4331_EXT_LNA (1<<2) /* 0 disable */
-#define CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */
-#define CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */
-#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */
-#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */
-#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */
-#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */
-#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */
-#define CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */
-#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */
-#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */
-#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */
+ /* 0 disable */
+#define CCTRL4331_BT_COEXIST (1<<0)
+ /* 0 SECI is disabled (JTAG functional) */
+#define CCTRL4331_SECI (1<<1)
+ /* 0 disable */
+#define CCTRL4331_EXT_LNA (1<<2)
+ /* sprom/gpio13-15 mux */
+#define CCTRL4331_SPROM_GPIO13_15 (1<<3)
+ /* 0 ext pa disable, 1 ext pa enabled */
+#define CCTRL4331_EXTPA_EN (1<<4)
+ /* set drive out GPIO_CLK on sprom_cs pin */
+#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5)
+ /* use sprom_cs pin as PCIE mdio interface */
+#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6)
+ /* aband extpa will be at gpio2/5 and sprom_dout */
+#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7)
+ /* override core control on pipe_AuxClkEnable */
+#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8)
+ /* override core control on pipe_AuxPowerDown */
+#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9)
+ /* pcie_auxclkenable */
+#define CCTRL4331_PCIE_AUXCLKEN (1<<10)
+ /* pcie_pipe_pllpowerdown */
+#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11)
+ /* enable bt_shd0 at gpio4 */
+#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16)
+ /* enable bt_shd1 at gpio5 */
+#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17)
/* 4331 Chip specific ChipStatus register bits */
-#define CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */
+ /* crystal frequency 20/40Mhz */
+#define CST4331_XTAL_FREQ 0x00000001
#define CST4331_SPROM_PRESENT 0x00000002
#define CST4331_OTP_PRESENT 0x00000004
#define CST4331_LDO_RF 0x00000008
@@ -110,19 +149,26 @@
#define CST4319_SPI_CPULESSUSB 0x00000001
#define CST4319_SPI_CLK_POL 0x00000002
#define CST4319_SPI_CLK_PH 0x00000008
-#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 /* gpio [7:6], SDIO CIS selection */
+ /* gpio [7:6], SDIO CIS selection */
+#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0
#define CST4319_SPROM_OTP_SEL_SHIFT 6
-#define CST4319_DEFCIS_SEL 0x00000000 /* use default CIS, OTP is powered up */
-#define CST4319_SPROM_SEL 0x00000040 /* use SPROM, OTP is powered up */
-#define CST4319_OTP_SEL 0x00000080 /* use OTP, OTP is powered up */
-#define CST4319_OTP_PWRDN 0x000000c0 /* use SPROM, OTP is powered down */
-#define CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */
+ /* use default CIS, OTP is powered up */
+#define CST4319_DEFCIS_SEL 0x00000000
+ /* use SPROM, OTP is powered up */
+#define CST4319_SPROM_SEL 0x00000040
+ /* use OTP, OTP is powered up */
+#define CST4319_OTP_SEL 0x00000080
+ /* use SPROM, OTP is powered down */
+#define CST4319_OTP_PWRDN 0x000000c0
+ /* gpio [8], sdio/usb mode */
+#define CST4319_SDIO_USB_MODE 0x00000100
#define CST4319_REMAP_SEL_MASK 0x00000600
#define CST4319_ILPDIV_EN 0x00000800
#define CST4319_XTAL_PD_POL 0x00001000
#define CST4319_LPO_SEL 0x00002000
#define CST4319_RES_INIT_MODE 0x0000c000
-#define CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */
+ /* PALDO is configured with external PNP */
+#define CST4319_PALDO_EXTPNP 0x00010000
#define CST4319_CBUCK_MODE_MASK 0x00060000
#define CST4319_CBUCK_MODE_BURST 0x00020000
#define CST4319_CBUCK_MODE_LPBURST 0x00060000
@@ -153,11 +199,8 @@
#define CST4313_SPROM_OTP_SEL_SHIFT 0
/* 4313 Chip specific ChipControl register bits */
-#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
-
-#define BCM47162_DMP() ((sih->chip == BCM47162_CHIP_ID) && \
- (sih->chiprev == 0) && \
- (sii->coreid[sii->curidx] == MIPS74K_CORE_ID))
+ /* 12 mA drive strengh for later 4313 */
+#define CCTRL_4313_12MA_LED_DRIVE 0x00000007
/* Manufacturer Ids */
#define MFGID_ARM 0x43b
@@ -227,9 +270,12 @@
#define SD_SG32 0x00000008
#define SD_SZ_ALIGN 0x00000fff
-#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
-#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal power-up */
-#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL power-down */
+/* PCI config space bit 4 for 4306c0 slow clock source */
+#define PCI_CFG_GPIO_SCS 0x10
+/* PCI config space GPIO 14 for Xtal power-up */
+#define PCI_CFG_GPIO_XTAL 0x40
+/* PCI config space GPIO 15 for PLL power-down */
+#define PCI_CFG_GPIO_PLL 0x80
/* power control defines */
#define PLL_DELAY 150 /* us pll on delay */
@@ -239,6 +285,82 @@
/* resetctrl */
#define AIRC_RESET 1
+#define NOREV -1 /* Invalid rev */
+
+/* GPIO Based LED powersave defines */
+#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
+#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
+
+/* When Srom support present, fields in sromcontrol */
+#define SRC_START 0x80000000
+#define SRC_BUSY 0x80000000
+#define SRC_OPCODE 0x60000000
+#define SRC_OP_READ 0x00000000
+#define SRC_OP_WRITE 0x20000000
+#define SRC_OP_WRDIS 0x40000000
+#define SRC_OP_WREN 0x60000000
+#define SRC_OTPSEL 0x00000010
+#define SRC_LOCK 0x00000008
+#define SRC_SIZE_MASK 0x00000006
+#define SRC_SIZE_1K 0x00000000
+#define SRC_SIZE_4K 0x00000002
+#define SRC_SIZE_16K 0x00000004
+#define SRC_SIZE_SHIFT 1
+#define SRC_PRESENT 0x00000001
+
+/* External PA enable mask */
+#define GPIO_CTRL_EPA_EN_MASK 0x40
+
+#define DEFAULT_GPIOTIMERVAL \
+ ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
+
+#define BADIDX (SI_MAXCORES + 1)
+
+/* Newer chips can access PCI/PCIE and CC core without requiring to change
+ * PCI BAR0 WIN
+ */
+#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \
+ (((si)->pub.buscoretype == PCI_CORE_ID) && \
+ (si)->pub.buscorerev >= 13))
+
+#define CCREGS_FAST(si) (((char __iomem *)((si)->curmap) + \
+ PCI_16KB0_CCREGS_OFFSET))
+
+#define IS_SIM(chippkg) \
+ ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
+
+/*
+ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts
+ * before after core switching to avoid invalid register accesss inside ISR.
+ */
+#define INTR_OFF(si, intr_val) \
+ if ((si)->intrsoff_fn && \
+ (si)->coreid[(si)->curidx] == (si)->dev_coreid) \
+ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg)
+
+#define INTR_RESTORE(si, intr_val) \
+ if ((si)->intrsrestore_fn && \
+ (si)->coreid[(si)->curidx] == (si)->dev_coreid) \
+ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val)
+
+#define PCI(si) ((si)->pub.buscoretype == PCI_CORE_ID)
+#define PCIE(si) ((si)->pub.buscoretype == PCIE_CORE_ID)
+
+#define PCI_FORCEHT(si) (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID))
+
+#ifdef BCMDBG
+#define SI_MSG(args) printk args
+#else
+#define SI_MSG(args)
+#endif /* BCMDBG */
+
+#define GOODCOREADDR(x, b) \
+ (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \
+ IS_ALIGNED((x), SI_CORE_SIZE))
+
+#define PCIEREGS(si) ((__iomem char *)((si)->curmap) + \
+ PCI_16KB0_PCIREGS_OFFSET)
+
struct aidmp {
u32 oobselina30; /* 0x000 */
u32 oobselina74; /* 0x004 */
@@ -360,7 +482,7 @@ struct aidmp {
/* EROM parsing */
static u32
-get_erom_ent(struct si_pub *sih, u32 **eromptr, u32 mask, u32 match)
+get_erom_ent(struct si_pub *sih, u32 __iomem **eromptr, u32 mask, u32 match)
{
u32 ent;
uint inv = 0, nom = 0;
@@ -386,16 +508,11 @@ get_erom_ent(struct si_pub *sih, u32 **eromptr, u32 mask, u32 match)
nom++;
}
- SI_VMSG(("%s: Returning ent 0x%08x\n", __func__, ent));
- if (inv + nom) {
- SI_VMSG((" after %d invalid and %d non-matching entries\n",
- inv, nom));
- }
return ent;
}
static u32
-get_asd(struct si_pub *sih, u32 **eromptr, uint sp, uint ad, uint st,
+get_asd(struct si_pub *sih, u32 __iomem **eromptr, uint sp, uint ad, uint st,
u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh)
{
u32 asd, sz, szd;
@@ -423,9 +540,6 @@ get_asd(struct si_pub *sih, u32 **eromptr, uint sp, uint ad, uint st,
} else
*sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
- SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
- sp, ad, st, *sizeh, *sizel, *addrh, *addrl));
-
return asd;
}
@@ -434,45 +548,28 @@ static void ai_hwfixup(struct si_info *sii)
}
/* parse the enumeration rom to identify all cores */
-void ai_scan(struct si_pub *sih, void *regs)
+static void ai_scan(struct si_pub *sih, struct chipcregs __iomem *cc)
{
- struct si_info *sii = SI_INFO(sih);
- chipcregs_t *cc = (chipcregs_t *) regs;
- u32 erombase, *eromptr, *eromlim;
+ struct si_info *sii = (struct si_info *)sih;
- erombase = R_REG(&cc->eromptr);
-
- switch (sih->bustype) {
- case SI_BUS:
- eromptr = (u32 *) REG_MAP(erombase, SI_CORE_SIZE);
- break;
+ u32 erombase;
+ u32 __iomem *eromptr, *eromlim;
+ void __iomem *regs = cc;
- case PCI_BUS:
- /* Set wrappers address */
- sii->curwrap = (void *)((unsigned long)regs + SI_CORE_SIZE);
-
- /* Now point the window at the erom */
- pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase);
- eromptr = regs;
- break;
+ erombase = R_REG(&cc->eromptr);
- case SPI_BUS:
- case SDIO_BUS:
- eromptr = (u32 *)(unsigned long)erombase;
- break;
+ /* Set wrappers address */
+ sii->curwrap = (void *)((unsigned long)cc + SI_CORE_SIZE);
- default:
- SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n",
- sih->bustype));
- return;
- }
+ /* Now point the window at the erom */
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase);
+ eromptr = regs;
eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32));
- SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n", regs, erombase, eromptr, eromlim));
while (eromptr < eromlim) {
u32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp;
u32 mpd, asd, addrl, addrh, sizel, sizeh;
- u32 *base;
+ u32 __iomem *base;
uint i, j, idx;
bool br;
@@ -481,8 +578,7 @@ void ai_scan(struct si_pub *sih, void *regs)
/* Grok a component */
cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
if (cia == (ER_END | ER_VALID)) {
- SI_VMSG(("Found END of erom after %d cores\n",
- sii->numcores));
+ /* Found END of erom */
ai_hwfixup(sii);
return;
}
@@ -490,7 +586,7 @@ void ai_scan(struct si_pub *sih, void *regs)
cib = get_erom_ent(sih, &eromptr, 0, 0);
if ((cib & ER_TAG) != ER_CI) {
- SI_ERROR(("CIA not followed by CIB\n"));
+ /* CIA not followed by CIB */
goto error;
}
@@ -502,8 +598,6 @@ void ai_scan(struct si_pub *sih, void *regs)
nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
- SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, " "nsw = %d, nmp = %d & nsp = %d\n", mfg, cid, crev, base, nmw, nsw, nmp, nsp));
-
if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
continue;
if ((nmw + nsw == 0)) {
@@ -511,9 +605,8 @@ void ai_scan(struct si_pub *sih, void *regs)
if (cid == OOB_ROUTER_CORE_ID) {
asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
&addrl, &addrh, &sizel, &sizeh);
- if (asd != 0) {
+ if (asd != 0)
sii->oob_router = addrl;
- }
}
continue;
}
@@ -527,12 +620,9 @@ void ai_scan(struct si_pub *sih, void *regs)
for (i = 0; i < nmp; i++) {
mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
if ((mpd & ER_TAG) != ER_MP) {
- SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
+ /* Not enough MP entries for component */
goto error;
}
- SI_VMSG((" Master port %d, mp: %d id: %d\n", i,
- (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
- (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
}
/* First Slave Address Descriptor should be port 0:
@@ -550,7 +640,7 @@ void ai_scan(struct si_pub *sih, void *regs)
br = true;
else if ((addrh != 0) || (sizeh != 0)
|| (sizel != SI_CORE_SIZE)) {
- SI_ERROR(("First Slave ASD for core 0x%04x malformed " "(0x%08x)\n", cid, asd));
+ /* First Slave ASD for core malformed */
goto error;
}
}
@@ -578,8 +668,7 @@ void ai_scan(struct si_pub *sih, void *regs)
&addrl, &addrh, &sizel, &sizeh);
} while (asd != 0);
if (j == 0) {
- SI_ERROR((" SP %d has no address descriptors\n",
- i));
+ /* SP has no address descriptors */
goto error;
}
}
@@ -590,11 +679,11 @@ void ai_scan(struct si_pub *sih, void *regs)
get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl,
&addrh, &sizel, &sizeh);
if (asd == 0) {
- SI_ERROR(("Missing descriptor for MW %d\n", i));
+ /* Missing descriptor for MW */
goto error;
}
if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
- SI_ERROR(("Master wrapper %d is not 4KB\n", i));
+ /* Master wrapper %d is not 4KB */
goto error;
}
if (i == 0)
@@ -608,11 +697,11 @@ void ai_scan(struct si_pub *sih, void *regs)
get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP,
&addrl, &addrh, &sizel, &sizeh);
if (asd == 0) {
- SI_ERROR(("Missing descriptor for SW %d\n", i));
+ /* Missing descriptor for SW */
goto error;
}
if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
- SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
+ /* Slave wrapper is not 4KB */
goto error;
}
if ((nmw == 0) && (i == 0))
@@ -627,62 +716,35 @@ void ai_scan(struct si_pub *sih, void *regs)
sii->numcores++;
}
- SI_ERROR(("Reached end of erom without finding END"));
-
error:
+ /* Reached end of erom without finding END */
sii->numcores = 0;
return;
}
-/* This function changes the logical "focus" to the indicated core.
- * Return the current core's virtual address.
+/*
+ * This function changes the logical "focus" to the indicated core.
+ * Return the current core's virtual address. Since each core starts with the
+ * same set of registers (BIST, clock control, etc), the returned address
+ * contains the first register of this 'common' register block (not to be
+ * confused with 'common core').
*/
-void *ai_setcoreidx(struct si_pub *sih, uint coreidx)
+void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx)
{
- struct si_info *sii = SI_INFO(sih);
+ struct si_info *sii = (struct si_info *)sih;
u32 addr = sii->coresba[coreidx];
u32 wrap = sii->wrapba[coreidx];
- void *regs;
if (coreidx >= sii->numcores)
return NULL;
- switch (sih->bustype) {
- case SI_BUS:
- /* map new one */
- if (!sii->regs[coreidx]) {
- sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
- }
- sii->curmap = regs = sii->regs[coreidx];
- if (!sii->wrappers[coreidx]) {
- sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
- }
- sii->curwrap = sii->wrappers[coreidx];
- break;
-
- case PCI_BUS:
- /* point bar0 window */
- pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr);
- regs = sii->curmap;
- /* point bar0 2nd 4KB window */
- pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap);
- break;
-
- case SPI_BUS:
- case SDIO_BUS:
- sii->curmap = regs = (void *)(unsigned long)addr;
- sii->curwrap = (void *)(unsigned long)wrap;
- break;
-
- default:
- regs = NULL;
- break;
- }
-
- sii->curmap = regs;
+ /* point bar0 window */
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr);
+ /* point bar0 2nd 4KB window */
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap);
sii->curidx = coreidx;
- return regs;
+ return sii->curmap;
}
/* Return the number of address spaces in current core */
@@ -697,7 +759,7 @@ u32 ai_addrspace(struct si_pub *sih, uint asidx)
struct si_info *sii;
uint cidx;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
cidx = sii->curidx;
if (asidx == 0)
@@ -705,7 +767,7 @@ u32 ai_addrspace(struct si_pub *sih, uint asidx)
else if (asidx == 1)
return sii->coresba2[cidx];
else {
- SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", __func__, asidx));
+ /* Need to parse the erom again to find addr space */
return 0;
}
}
@@ -716,7 +778,7 @@ u32 ai_addrspacesize(struct si_pub *sih, uint asidx)
struct si_info *sii;
uint cidx;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
cidx = sii->curidx;
if (asidx == 0)
@@ -724,7 +786,7 @@ u32 ai_addrspacesize(struct si_pub *sih, uint asidx)
else if (asidx == 1)
return sii->coresba2_size[cidx];
else {
- SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n", __func__, asidx));
+ /* Need to parse the erom again to find addr */
return 0;
}
}
@@ -734,11 +796,7 @@ uint ai_flag(struct si_pub *sih)
struct si_info *sii;
struct aidmp *ai;
- sii = SI_INFO(sih);
- if (BCM47162_DMP()) {
- SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __func__));
- return sii->curidx;
- }
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
return R_REG(&ai->oobselouta30) & 0x1f;
@@ -753,7 +811,7 @@ uint ai_corevendor(struct si_pub *sih)
struct si_info *sii;
u32 cia;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
cia = sii->cia[sii->curidx];
return (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
}
@@ -763,7 +821,7 @@ uint ai_corerev(struct si_pub *sih)
struct si_info *sii;
u32 cib;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
cib = sii->cib[sii->curidx];
return (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
}
@@ -773,7 +831,7 @@ bool ai_iscoreup(struct si_pub *sih)
struct si_info *sii;
struct aidmp *ai;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) ==
@@ -787,13 +845,7 @@ void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val)
struct aidmp *ai;
u32 w;
- sii = SI_INFO(sih);
-
- if (BCM47162_DMP()) {
- SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
- __func__));
- return;
- }
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
@@ -809,13 +861,7 @@ u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val)
struct aidmp *ai;
u32 w;
- sii = SI_INFO(sih);
- if (BCM47162_DMP()) {
- SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
- __func__));
- return 0;
- }
-
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
if (mask || val) {
@@ -826,18 +872,35 @@ u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val)
return R_REG(&ai->ioctrl);
}
+/* return true if PCIE capability exists in the pci config space */
+static bool ai_ispcie(struct si_info *sii)
+{
+ u8 cap_ptr;
+
+ cap_ptr =
+ pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL,
+ NULL);
+ if (!cap_ptr)
+ return false;
+
+ return true;
+}
+
+static bool ai_buscore_prep(struct si_info *sii)
+{
+ /* kludge to enable the clock on the 4306 which lacks a slowclock */
+ if (!ai_ispcie(sii))
+ ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
+ return true;
+}
+
u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val)
{
struct si_info *sii;
struct aidmp *ai;
u32 w;
- sii = SI_INFO(sih);
- if (BCM47162_DMP()) {
- SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0", __func__));
- return 0;
- }
-
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
if (mask || val) {
@@ -848,74 +911,13 @@ u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val)
return R_REG(&ai->iostatus);
}
-/* *************** from siutils.c ************** */
-/* local prototypes */
-static struct si_info *ai_doattach(struct si_info *sii, void *regs,
- uint bustype, void *sdh, char **vars,
- uint *varsz);
-static bool ai_buscore_prep(struct si_info *sii, uint bustype);
-static bool ai_buscore_setup(struct si_info *sii, chipcregs_t *cc, uint bustype,
- u32 savewin, uint *origidx, void *regs);
-static void ai_nvram_process(struct si_info *sii, char *pvars);
-
-/* dev path concatenation util */
-static char *ai_devpathvar(struct si_pub *sih, char *var, int len,
- const char *name);
-static bool _ai_clkctl_cc(struct si_info *sii, uint mode);
-static bool ai_ispcie(struct si_info *sii);
-
-/* global variable to indicate reservation/release of gpio's */
-static u32 ai_gpioreservation;
-
-/*
- * Allocate a si handle.
- * devid - pci device id (used to determine chip#)
- * osh - opaque OS handle
- * regs - virtual address of initial core registers
- * bustype - pci/sb/sdio/etc
- * vars - pointer to a pointer area for "environment" variables
- * varsz - pointer to int to return the size of the vars
- */
-struct si_pub *ai_attach(void *regs, uint bustype,
- void *sdh, char **vars, uint *varsz)
-{
- struct si_info *sii;
-
- /* alloc struct si_info */
- sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC);
- if (sii == NULL) {
- SI_ERROR(("si_attach: malloc failed!\n"));
- return NULL;
- }
-
- if (ai_doattach(sii, regs, bustype, sdh, vars, varsz) ==
- NULL) {
- kfree(sii);
- return NULL;
- }
- sii->vars = vars ? *vars : NULL;
- sii->varsz = varsz ? *varsz : 0;
-
- return (struct si_pub *) sii;
-}
-
-/* global kernel resource */
-static struct si_info ksii;
-
-static bool ai_buscore_prep(struct si_info *sii, uint bustype)
-{
- /* kludge to enable the clock on the 4306 which lacks a slowclock */
- if (bustype == PCI_BUS && !ai_ispcie(sii))
- ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
- return true;
-}
-
-static bool ai_buscore_setup(struct si_info *sii, chipcregs_t *cc, uint bustype,
- u32 savewin, uint *origidx, void *regs)
+static bool
+ai_buscore_setup(struct si_info *sii, u32 savewin, uint *origidx)
{
bool pci, pcie;
uint i;
uint pciidx, pcieidx, pcirev, pcierev;
+ struct chipcregs __iomem *cc;
cc = ai_setcoreidx(&sii->pub, SI_CC_IDX);
@@ -955,25 +957,19 @@ static bool ai_buscore_setup(struct si_info *sii, chipcregs_t *cc, uint bustype,
cid = ai_coreid(&sii->pub);
crev = ai_corerev(&sii->pub);
- /* Display cores found */
- SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n",
- i, cid, crev, sii->coresba[i], sii->regs[i]));
-
- if (bustype == PCI_BUS) {
- if (cid == PCI_CORE_ID) {
- pciidx = i;
- pcirev = crev;
- pci = true;
- } else if (cid == PCIE_CORE_ID) {
- pcieidx = i;
- pcierev = crev;
- pcie = true;
- }
+ if (cid == PCI_CORE_ID) {
+ pciidx = i;
+ pcirev = crev;
+ pci = true;
+ } else if (cid == PCIE_CORE_ID) {
+ pcieidx = i;
+ pcierev = crev;
+ pcie = true;
}
/* find the core idx before entering this func. */
if ((savewin && (savewin == sii->coresba[i])) ||
- (regs == sii->regs[i]))
+ (cc == sii->regs[i]))
*origidx = i;
}
@@ -993,25 +989,19 @@ static bool ai_buscore_setup(struct si_info *sii, chipcregs_t *cc, uint bustype,
sii->pub.buscoreidx = pcieidx;
}
- SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx,
- sii->pub.buscoretype, sii->pub.buscorerev));
-
/* fixup necessary chip/core configurations */
- if (sii->pub.bustype == PCI_BUS) {
- if (SI_FAST(sii)) {
- if (!sii->pch) {
- sii->pch = (void *)pcicore_init(
- &sii->pub, sii->pbus,
- (void *)PCIEREGS(sii));
- if (sii->pch == NULL)
- return false;
- }
- }
- if (ai_pci_fixcfg(&sii->pub)) {
- SI_ERROR(("si_doattach: si_pci_fixcfg failed\n"));
- return false;
+ if (SI_FAST(sii)) {
+ if (!sii->pch) {
+ sii->pch = pcicore_init(&sii->pub, sii->pbus,
+ (__iomem void *)PCIEREGS(sii));
+ if (sii->pch == NULL)
+ return false;
}
}
+ if (ai_pci_fixcfg(&sii->pub)) {
+ /* si_doattach: si_pci_fixcfg failed */
+ return false;
+ }
/* return to the original core */
ai_setcoreidx(&sii->pub, *origidx);
@@ -1019,63 +1009,27 @@ static bool ai_buscore_setup(struct si_info *sii, chipcregs_t *cc, uint bustype,
return true;
}
-static __used void ai_nvram_process(struct si_info *sii, char *pvars)
+/*
+ * get boardtype and boardrev
+ */
+static __used void ai_nvram_process(struct si_info *sii)
{
uint w = 0;
- /* get boardtype and boardrev */
- switch (sii->pub.bustype) {
- case PCI_BUS:
- /* do a pci config read to get subsystem id and subvendor id */
- pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w);
- /* Let nvram variables override subsystem Vend/ID */
- sii->pub.boardvendor = (u16)ai_getdevpathintvar(&sii->pub,
- "boardvendor");
- if (sii->pub.boardvendor == 0)
- sii->pub.boardvendor = w & 0xffff;
- else
- SI_ERROR(("Overriding boardvendor: 0x%x instead of "
- "0x%x\n", sii->pub.boardvendor, w & 0xffff));
- sii->pub.boardtype = (u16)ai_getdevpathintvar(&sii->pub,
- "boardtype");
- if (sii->pub.boardtype == 0)
- sii->pub.boardtype = (w >> 16) & 0xffff;
- else
- SI_ERROR(("Overriding boardtype: 0x%x instead of 0x%x\n"
- , sii->pub.boardtype, (w >> 16) & 0xffff));
- break;
-
- sii->pub.boardvendor = getintvar(pvars, "manfid");
- sii->pub.boardtype = getintvar(pvars, "prodid");
- break;
-
- case SI_BUS:
- case JTAG_BUS:
- sii->pub.boardvendor = PCI_VENDOR_ID_BROADCOM;
- sii->pub.boardtype = getintvar(pvars, "prodid");
- if (pvars == NULL || (sii->pub.boardtype == 0)) {
- sii->pub.boardtype = getintvar(NULL, "boardtype");
- if (sii->pub.boardtype == 0)
- sii->pub.boardtype = 0xffff;
- }
- break;
- }
-
- if (sii->pub.boardtype == 0) {
- SI_ERROR(("si_doattach: unknown board type\n"));
- }
+ /* do a pci config read to get subsystem id and subvendor id */
+ pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w);
- sii->pub.boardflags = getintvar(pvars, "boardflags");
+ sii->pub.boardvendor = w & 0xffff;
+ sii->pub.boardtype = (w >> 16) & 0xffff;
+ sii->pub.boardflags = getintvar(&sii->pub, BRCMS_SROM_BOARDFLAGS);
}
static struct si_info *ai_doattach(struct si_info *sii,
- void *regs, uint bustype, void *pbus,
- char **vars, uint *varsz)
+ void __iomem *regs, struct pci_dev *pbus)
{
struct si_pub *sih = &sii->pub;
u32 w, savewin;
- chipcregs_t *cc;
- char *pvars = NULL;
+ struct chipcregs __iomem *cc;
uint socitype;
uint origidx;
@@ -1088,37 +1042,18 @@ static struct si_info *ai_doattach(struct si_info *sii,
sii->curmap = regs;
sii->pbus = pbus;
- /* check to see if we are a si core mimic'ing a pci core */
- if (bustype == PCI_BUS) {
- pci_read_config_dword(sii->pbus, PCI_SPROM_CONTROL, &w);
- if (w == 0xffffffff) {
- SI_ERROR(("%s: incoming bus is PCI but it's a lie, "
- " switching to SI devid:0x%x\n",
- __func__, devid));
- bustype = SI_BUS;
- }
- }
-
/* find Chipcommon address */
- if (bustype == PCI_BUS) {
- pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin);
- if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
- savewin = SI_ENUM_BASE;
- pci_write_config_dword(sii->pbus, PCI_BAR0_WIN,
- SI_ENUM_BASE);
- cc = (chipcregs_t *) regs;
- } else {
- cc = (chipcregs_t *) REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
- }
+ pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin);
+ if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
+ savewin = SI_ENUM_BASE;
- sih->bustype = bustype;
+ pci_write_config_dword(sii->pbus, PCI_BAR0_WIN,
+ SI_ENUM_BASE);
+ cc = (struct chipcregs __iomem *) regs;
/* bus/core/clk setup for register access */
- if (!ai_buscore_prep(sii, bustype)) {
- SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n",
- bustype));
+ if (!ai_buscore_prep(sii))
return NULL;
- }
/*
* ChipID recognition.
@@ -1134,67 +1069,59 @@ static struct si_info *ai_doattach(struct si_info *sii,
sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
- sih->issim = IS_SIM(sih->chippkg);
+ sih->issim = false;
/* scan for cores */
if (socitype == SOCI_AI) {
SI_MSG(("Found chip type AI (0x%08x)\n", w));
/* pass chipc address instead of original core base */
- ai_scan(&sii->pub, (void *)cc);
+ ai_scan(&sii->pub, cc);
} else {
- SI_ERROR(("Found chip of unknown type (0x%08x)\n", w));
+ /* Found chip of unknown type */
return NULL;
}
/* no cores found, bail out */
- if (sii->numcores == 0) {
- SI_ERROR(("si_doattach: could not find any cores\n"));
+ if (sii->numcores == 0)
return NULL;
- }
+
/* bus/core/clk setup */
origidx = SI_CC_IDX;
- if (!ai_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
- SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
+ if (!ai_buscore_setup(sii, savewin, &origidx))
goto exit;
- }
/* Init nvram from sprom/otp if they exist */
- if (srom_var_init
- (&sii->pub, bustype, regs, vars, varsz)) {
- SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n"));
+ if (srom_var_init(&sii->pub, cc))
goto exit;
- }
- pvars = vars ? *vars : NULL;
- ai_nvram_process(sii, pvars);
+
+ ai_nvram_process(sii);
/* === NVRAM, clock is ready === */
- cc = (chipcregs_t *) ai_setcore(sih, CC_CORE_ID, 0);
+ cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0);
W_REG(&cc->gpiopullup, 0);
W_REG(&cc->gpiopulldown, 0);
ai_setcoreidx(sih, origidx);
/* PMU specific initializations */
- if (PMUCTL_ENAB(sih)) {
+ if (sih->cccaps & CC_CAP_PMU) {
u32 xtalfreq;
si_pmu_init(sih);
si_pmu_chip_init(sih);
- xtalfreq = getintvar(pvars, "xtalfreq");
- /* If xtalfreq var not available, try to measure it */
- if (xtalfreq == 0)
- xtalfreq = si_pmu_measure_alpclk(sih);
+
+ xtalfreq = si_pmu_measure_alpclk(sih);
si_pmu_pll_init(sih, xtalfreq);
si_pmu_res_init(sih);
si_pmu_swreg_init(sih);
}
/* setup the GPIO based LED powersave register */
- w = getintvar(pvars, "leddc");
+ w = getintvar(sih, BRCMS_SROM_LEDDC);
if (w == 0)
w = DEFAULT_GPIOTIMERVAL;
- ai_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, gpiotimerval), ~0, w);
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, gpiotimerval),
+ ~0, w);
- if (PCIE(sii)) {
- pcicore_attach(sii->pch, pvars, SI_DOATTACH);
- }
+ if (PCIE(sii))
+ pcicore_attach(sii->pch, SI_DOATTACH);
if (sih->chip == BCM43224_CHIP_ID) {
/*
@@ -1204,7 +1131,7 @@ static struct si_info *ai_doattach(struct si_info *sii,
if (sih->chiprev == 0) {
SI_MSG(("Applying 43224A0 WARs\n"));
ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol),
+ offsetof(struct chipcregs, chipcontrol),
CCTRL43224_GPIO_TOGGLE,
CCTRL43224_GPIO_TOGGLE);
si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE,
@@ -1228,45 +1155,58 @@ static struct si_info *ai_doattach(struct si_info *sii,
}
return sii;
+
exit:
- if (sih->bustype == PCI_BUS) {
- if (sii->pch)
- pcicore_deinit(sii->pch);
- sii->pch = NULL;
- }
+ if (sii->pch)
+ pcicore_deinit(sii->pch);
+ sii->pch = NULL;
return NULL;
}
+/*
+ * Allocate a si handle.
+ * devid - pci device id (used to determine chip#)
+ * osh - opaque OS handle
+ * regs - virtual address of initial core registers
+ */
+struct si_pub *
+ai_attach(void __iomem *regs, struct pci_dev *sdh)
+{
+ struct si_info *sii;
+
+ /* alloc struct si_info */
+ sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC);
+ if (sii == NULL)
+ return NULL;
+
+ if (ai_doattach(sii, regs, sdh) == NULL) {
+ kfree(sii);
+ return NULL;
+ }
+
+ return (struct si_pub *) sii;
+}
+
/* may be called with core in reset */
void ai_detach(struct si_pub *sih)
{
struct si_info *sii;
- uint idx;
struct si_pub *si_local = NULL;
memcpy(&si_local, &sih, sizeof(struct si_pub **));
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
if (sii == NULL)
return;
- if (sih->bustype == SI_BUS)
- for (idx = 0; idx < SI_MAXCORES; idx++)
- if (sii->regs[idx]) {
- iounmap(sii->regs[idx]);
- sii->regs[idx] = NULL;
- }
-
- if (sih->bustype == PCI_BUS) {
- if (sii->pch)
- pcicore_deinit(sii->pch);
- sii->pch = NULL;
- }
+ if (sii->pch)
+ pcicore_deinit(sii->pch);
+ sii->pch = NULL;
- if (sii != &ksii)
- kfree(sii);
+ srom_free_vars(sih);
+ kfree(sii);
}
/* register driver interrupt disabling and restoring callback functions */
@@ -1277,11 +1217,11 @@ ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn,
{
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
sii->intr_arg = intr_arg;
- sii->intrsoff_fn = (si_intrsoff_t) intrsoff_fn;
- sii->intrsrestore_fn = (si_intrsrestore_t) intrsrestore_fn;
- sii->intrsenabled_fn = (si_intrsenabled_t) intrsenabled_fn;
+ sii->intrsoff_fn = (u32 (*)(void *)) intrsoff_fn;
+ sii->intrsrestore_fn = (void (*) (void *, u32)) intrsrestore_fn;
+ sii->intrsenabled_fn = (bool (*)(void *)) intrsenabled_fn;
/* save current core id. when this function called, the current core
* must be the core which provides driver functions(il, et, wl, etc.)
*/
@@ -1292,7 +1232,7 @@ void ai_deregister_intr_callback(struct si_pub *sih)
{
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
sii->intrsoff_fn = NULL;
}
@@ -1300,7 +1240,7 @@ uint ai_coreid(struct si_pub *sih)
{
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
return sii->coreid[sii->curidx];
}
@@ -1308,7 +1248,7 @@ uint ai_coreidx(struct si_pub *sih)
{
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
return sii->curidx;
}
@@ -1324,7 +1264,7 @@ uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit)
uint found;
uint i;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
found = 0;
@@ -1344,25 +1284,25 @@ uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit)
* Moreover, callers should keep interrupts off during switching
* out of and back to d11 core.
*/
-void *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit)
+void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit)
{
uint idx;
idx = ai_findcoreidx(sih, coreid, coreunit);
- if (!GOODIDX(idx))
+ if (idx >= SI_MAXCORES)
return NULL;
return ai_setcoreidx(sih, idx);
}
/* Turn off interrupt as required by ai_setcore, before switch core */
-void *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx,
- uint *intr_val)
+void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx,
+ uint *intr_val)
{
- void *cc;
+ void __iomem *cc;
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
if (SI_FAST(sii)) {
/* Overloading the origidx variable to remember the coreid,
@@ -1371,9 +1311,9 @@ void *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx,
*/
*origidx = coreid;
if (coreid == CC_CORE_ID)
- return (void *)CCREGS_FAST(sii);
+ return CCREGS_FAST(sii);
else if (coreid == sih->buscoretype)
- return (void *)PCIEREGS(sii);
+ return PCIEREGS(sii);
}
INTR_OFF(sii, *intr_val);
*origidx = sii->curidx;
@@ -1386,7 +1326,7 @@ void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val)
{
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
if (SI_FAST(sii)
&& ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype)))
return;
@@ -1397,7 +1337,7 @@ void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val)
void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val)
{
- struct si_info *sii = SI_INFO(sih);
+ struct si_info *sii = (struct si_info *)sih;
u32 *w = (u32 *) sii->curwrap;
W_REG(w + (offset / 4), val);
return;
@@ -1417,54 +1357,40 @@ uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask,
uint val)
{
uint origidx = 0;
- u32 *r = NULL;
+ u32 __iomem *r = NULL;
uint w;
uint intr_val = 0;
bool fast = false;
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
if (coreidx >= SI_MAXCORES)
return 0;
- if (sih->bustype == SI_BUS) {
- /* If internal bus, we can always get at everything */
+ /*
+ * If pci/pcie, we can get at pci/pcie regs
+ * and on newer cores to chipc
+ */
+ if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
+ /* Chipc registers are mapped at 12KB */
fast = true;
- /* map if does not exist */
- if (!sii->regs[coreidx]) {
- sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx],
- SI_CORE_SIZE);
- }
- r = (u32 *) ((unsigned char *) sii->regs[coreidx] + regoff);
- } else if (sih->bustype == PCI_BUS) {
+ r = (u32 __iomem *)((__iomem char *)sii->curmap +
+ PCI_16KB0_CCREGS_OFFSET + regoff);
+ } else if (sii->pub.buscoreidx == coreidx) {
/*
- * If pci/pcie, we can get at pci/pcie regs
- * and on newer cores to chipc
+ * pci registers are at either in the last 2KB of
+ * an 8KB window or, in pcie and pci rev 13 at 8KB
*/
- if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
- /* Chipc registers are mapped at 12KB */
-
- fast = true;
- r = (u32 *) ((char *)sii->curmap +
- PCI_16KB0_CCREGS_OFFSET + regoff);
- } else if (sii->pub.buscoreidx == coreidx) {
- /*
- * pci registers are at either in the last 2KB of
- * an 8KB window or, in pcie and pci rev 13 at 8KB
- */
- fast = true;
- if (SI_FAST(sii))
- r = (u32 *) ((char *)sii->curmap +
- PCI_16KB0_PCIREGS_OFFSET +
- regoff);
- else
- r = (u32 *) ((char *)sii->curmap +
- ((regoff >= SBCONFIGOFF) ?
- PCI_BAR0_PCISBR_OFFSET :
- PCI_BAR0_PCIREGS_OFFSET) +
- regoff);
- }
+ fast = true;
+ if (SI_FAST(sii))
+ r = (u32 __iomem *)((__iomem char *)sii->curmap +
+ PCI_16KB0_PCIREGS_OFFSET + regoff);
+ else
+ r = (u32 __iomem *)((__iomem char *)sii->curmap +
+ ((regoff >= SBCONFIGOFF) ?
+ PCI_BAR0_PCISBR_OFFSET :
+ PCI_BAR0_PCIREGS_OFFSET) + regoff);
}
if (!fast) {
@@ -1474,8 +1400,8 @@ uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask,
origidx = ai_coreidx(&sii->pub);
/* switch core */
- r = (u32 *) ((unsigned char *) ai_setcoreidx(&sii->pub, coreidx)
- + regoff);
+ r = (u32 __iomem *) ((unsigned char __iomem *)
+ ai_setcoreidx(&sii->pub, coreidx) + regoff);
}
/* mask and set */
@@ -1504,7 +1430,7 @@ void ai_core_disable(struct si_pub *sih, u32 bits)
u32 dummy;
struct aidmp *ai;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
@@ -1531,7 +1457,7 @@ void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits)
struct aidmp *ai;
u32 dummy;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
ai = sii->curwrap;
/*
@@ -1556,19 +1482,18 @@ void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits)
/* return the slow clock source - LPO, XTAL, or PCI */
static uint ai_slowclk_src(struct si_info *sii)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
u32 val;
if (sii->pub.ccrev < 6) {
- if (sii->pub.bustype == PCI_BUS) {
- pci_read_config_dword(sii->pbus, PCI_GPIO_OUT,
- &val);
- if (val & PCI_CFG_GPIO_SCS)
- return SCC_SS_PCI;
- }
+ pci_read_config_dword(sii->pbus, PCI_GPIO_OUT,
+ &val);
+ if (val & PCI_CFG_GPIO_SCS)
+ return SCC_SS_PCI;
return SCC_SS_XTAL;
} else if (sii->pub.ccrev < 10) {
- cc = (chipcregs_t *) ai_setcoreidx(&sii->pub, sii->curidx);
+ cc = (struct chipcregs __iomem *)
+ ai_setcoreidx(&sii->pub, sii->curidx);
return R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK;
} else /* Insta-clock */
return SCC_SS_XTAL;
@@ -1578,7 +1503,8 @@ static uint ai_slowclk_src(struct si_info *sii)
* return the ILP (slowclock) min or max frequency
* precondition: we've established the chip has dynamic clk control
*/
-static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, chipcregs_t *cc)
+static uint ai_slowclk_freq(struct si_info *sii, bool max_freq,
+ struct chipcregs __iomem *cc)
{
u32 slowclk;
uint div;
@@ -1612,9 +1538,9 @@ static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, chipcregs_t *cc)
return 0;
}
-static void ai_clkctl_setdelay(struct si_info *sii, void *chipcregs)
+static void
+ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc)
{
- chipcregs_t *cc = (chipcregs_t *) chipcregs;
uint slowmaxfreq, pll_delay, slowclk;
uint pll_on_delay, fref_sel_delay;
@@ -1646,21 +1572,22 @@ void ai_clkctl_init(struct si_pub *sih)
{
struct si_info *sii;
uint origidx = 0;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
bool fast;
- if (!CCCTL_ENAB(sih))
+ if (!(sih->cccaps & CC_CAP_PWR_CTL))
return;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
fast = SI_FAST(sii);
if (!fast) {
origidx = sii->curidx;
- cc = (chipcregs_t *) ai_setcore(sih, CC_CORE_ID, 0);
+ cc = (struct chipcregs __iomem *)
+ ai_setcore(sih, CC_CORE_ID, 0);
if (cc == NULL)
return;
} else {
- cc = (chipcregs_t *) CCREGS_FAST(sii);
+ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii);
if (cc == NULL)
return;
}
@@ -1670,7 +1597,7 @@ void ai_clkctl_init(struct si_pub *sih)
SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK,
(ILP_DIV_1MHZ << SYCC_CD_SHIFT));
- ai_clkctl_setdelay(sii, (void *)cc);
+ ai_clkctl_setdelay(sii, cc);
if (!fast)
ai_setcoreidx(sih, origidx);
@@ -1684,21 +1611,21 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih)
{
struct si_info *sii;
uint origidx = 0;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint slowminfreq;
u16 fpdelay;
uint intr_val = 0;
bool fast;
- sii = SI_INFO(sih);
- if (PMUCTL_ENAB(sih)) {
+ sii = (struct si_info *)sih;
+ if (sih->cccaps & CC_CAP_PMU) {
INTR_OFF(sii, intr_val);
fpdelay = si_pmu_fast_pwrup_delay(sih);
INTR_RESTORE(sii, intr_val);
return fpdelay;
}
- if (!CCCTL_ENAB(sih))
+ if (!(sih->cccaps & CC_CAP_PWR_CTL))
return 0;
fast = SI_FAST(sii);
@@ -1706,11 +1633,12 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih)
if (!fast) {
origidx = sii->curidx;
INTR_OFF(sii, intr_val);
- cc = (chipcregs_t *) ai_setcore(sih, CC_CORE_ID, 0);
+ cc = (struct chipcregs __iomem *)
+ ai_setcore(sih, CC_CORE_ID, 0);
if (cc == NULL)
goto done;
} else {
- cc = (chipcregs_t *) CCREGS_FAST(sii);
+ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii);
if (cc == NULL)
goto done;
}
@@ -1733,99 +1661,68 @@ int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on)
struct si_info *sii;
u32 in, out, outen;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
- switch (sih->bustype) {
-
- case PCI_BUS:
- /* pcie core doesn't have any mapping to control the xtal pu */
- if (PCIE(sii))
- return -1;
+ /* pcie core doesn't have any mapping to control the xtal pu */
+ if (PCIE(sii))
+ return -1;
- pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in);
- pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out);
- pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen);
+ pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in);
+ pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out);
+ pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen);
- /*
- * Avoid glitching the clock if GPRS is already using it.
- * We can't actually read the state of the PLLPD so we infer it
- * by the value of XTAL_PU which *is* readable via gpioin.
- */
- if (on && (in & PCI_CFG_GPIO_XTAL))
- return 0;
+ /*
+ * Avoid glitching the clock if GPRS is already using it.
+ * We can't actually read the state of the PLLPD so we infer it
+ * by the value of XTAL_PU which *is* readable via gpioin.
+ */
+ if (on && (in & PCI_CFG_GPIO_XTAL))
+ return 0;
- if (what & XTAL)
- outen |= PCI_CFG_GPIO_XTAL;
- if (what & PLL)
- outen |= PCI_CFG_GPIO_PLL;
-
- if (on) {
- /* turn primary xtal on */
- if (what & XTAL) {
- out |= PCI_CFG_GPIO_XTAL;
- if (what & PLL)
- out |= PCI_CFG_GPIO_PLL;
- pci_write_config_dword(sii->pbus,
- PCI_GPIO_OUT, out);
- pci_write_config_dword(sii->pbus,
- PCI_GPIO_OUTEN, outen);
- udelay(XTAL_ON_DELAY);
- }
+ if (what & XTAL)
+ outen |= PCI_CFG_GPIO_XTAL;
+ if (what & PLL)
+ outen |= PCI_CFG_GPIO_PLL;
- /* turn pll on */
- if (what & PLL) {
- out &= ~PCI_CFG_GPIO_PLL;
- pci_write_config_dword(sii->pbus,
- PCI_GPIO_OUT, out);
- mdelay(2);
- }
- } else {
- if (what & XTAL)
- out &= ~PCI_CFG_GPIO_XTAL;
+ if (on) {
+ /* turn primary xtal on */
+ if (what & XTAL) {
+ out |= PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pbus,
PCI_GPIO_OUT, out);
pci_write_config_dword(sii->pbus,
PCI_GPIO_OUTEN, outen);
+ udelay(XTAL_ON_DELAY);
}
- default:
- return -1;
+ /* turn pll on */
+ if (what & PLL) {
+ out &= ~PCI_CFG_GPIO_PLL;
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUT, out);
+ mdelay(2);
+ }
+ } else {
+ if (what & XTAL)
+ out &= ~PCI_CFG_GPIO_XTAL;
+ if (what & PLL)
+ out |= PCI_CFG_GPIO_PLL;
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUT, out);
+ pci_write_config_dword(sii->pbus,
+ PCI_GPIO_OUTEN, outen);
}
return 0;
}
-/*
- * clock control policy function throught chipcommon
- *
- * set dynamic clk control mode (forceslow, forcefast, dynamic)
- * returns true if we are forcing fast clock
- * this is a wrapper over the next internal function
- * to allow flexible policy settings for outside caller
- */
-bool ai_clkctl_cc(struct si_pub *sih, uint mode)
-{
- struct si_info *sii;
-
- sii = SI_INFO(sih);
-
- /* chipcommon cores prior to rev6 don't support dynamic clock control */
- if (sih->ccrev < 6)
- return false;
-
- if (PCI_FORCEHT(sii))
- return mode == CLK_FAST;
-
- return _ai_clkctl_cc(sii, mode);
-}
-
/* clk control mechanism through chipcommon, no policy checking */
static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
{
uint origidx = 0;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
u32 scc;
uint intr_val = 0;
bool fast = SI_FAST(sii);
@@ -1837,20 +1734,15 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
if (!fast) {
INTR_OFF(sii, intr_val);
origidx = sii->curidx;
-
- if ((sii->pub.bustype == SI_BUS) &&
- ai_setcore(&sii->pub, MIPS33_CORE_ID, 0) &&
- (ai_corerev(&sii->pub) <= 7) && (sii->pub.ccrev >= 10))
- goto done;
-
- cc = (chipcregs_t *) ai_setcore(&sii->pub, CC_CORE_ID, 0);
+ cc = (struct chipcregs __iomem *)
+ ai_setcore(&sii->pub, CC_CORE_ID, 0);
} else {
- cc = (chipcregs_t *) CCREGS_FAST(sii);
+ cc = (struct chipcregs __iomem *) CCREGS_FAST(sii);
if (cc == NULL)
goto done;
}
- if (!CCCTL_ENAB(&sii->pub) && (sii->pub.ccrev < 20))
+ if (!(sii->pub.cccaps & CC_CAP_PWR_CTL) && (sii->pub.ccrev < 20))
goto done;
switch (mode) {
@@ -1870,7 +1762,7 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
}
/* wait for the PLL */
- if (PMUCTL_ENAB(&sii->pub)) {
+ if (sii->pub.cccaps & CC_CAP_PMU) {
u32 htavail = CCS_HTAVAIL;
SPINWAIT(((R_REG(&cc->clk_ctl_st) & htavail)
== 0), PMU_MAX_TRANSITION_DLY);
@@ -1913,7 +1805,31 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
return mode == CLK_FAST;
}
-/* Build device path. Support SI, PCI, and JTAG for now. */
+/*
+ * clock control policy function throught chipcommon
+ *
+ * set dynamic clk control mode (forceslow, forcefast, dynamic)
+ * returns true if we are forcing fast clock
+ * this is a wrapper over the next internal function
+ * to allow flexible policy settings for outside caller
+ */
+bool ai_clkctl_cc(struct si_pub *sih, uint mode)
+{
+ struct si_info *sii;
+
+ sii = (struct si_info *)sih;
+
+ /* chipcommon cores prior to rev6 don't support dynamic clock control */
+ if (sih->ccrev < 6)
+ return false;
+
+ if (PCI_FORCEHT(sii))
+ return mode == CLK_FAST;
+
+ return _ai_clkctl_cc(sii, mode);
+}
+
+/* Build device path */
int ai_devpath(struct si_pub *sih, char *path, int size)
{
int slen;
@@ -1921,22 +1837,10 @@ int ai_devpath(struct si_pub *sih, char *path, int size)
if (!path || size <= 0)
return -1;
- switch (sih->bustype) {
- case SI_BUS:
- case JTAG_BUS:
- slen = snprintf(path, (size_t) size, "sb/%u/", ai_coreidx(sih));
- break;
- case PCI_BUS:
- slen = snprintf(path, (size_t) size, "pci/%u/%u/",
- ((struct pci_dev *)((SI_INFO(sih))->pbus))->bus->number,
- PCI_SLOT(
- ((struct pci_dev *)((SI_INFO(sih))->pbus))->devfn));
- break;
-
- default:
- slen = -1;
- break;
- }
+ slen = snprintf(path, (size_t) size, "pci/%u/%u/",
+ ((struct si_info *)sih)->pbus->bus->number,
+ PCI_SLOT(((struct pci_dev *)
+ (((struct si_info *)(sih))->pbus))->devfn));
if (slen < 0 || slen >= size) {
path[0] = '\0';
@@ -1946,95 +1850,11 @@ int ai_devpath(struct si_pub *sih, char *path, int size)
return 0;
}
-/* Get a variable, but only if it has a devpath prefix */
-char *ai_getdevpathvar(struct si_pub *sih, const char *name)
-{
- char varname[SI_DEVPATH_BUFSZ + 32];
-
- ai_devpathvar(sih, varname, sizeof(varname), name);
-
- return getvar(NULL, varname);
-}
-
-/* Get a variable, but only if it has a devpath prefix */
-int ai_getdevpathintvar(struct si_pub *sih, const char *name)
-{
-#if defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS)
- return getintvar(NULL, name);
-#else
- char varname[SI_DEVPATH_BUFSZ + 32];
-
- ai_devpathvar(sih, varname, sizeof(varname), name);
-
- return getintvar(NULL, varname);
-#endif
-}
-
-char *ai_getnvramflvar(struct si_pub *sih, const char *name)
-{
- return getvar(NULL, name);
-}
-
-/* Concatenate the dev path with a varname into the given 'var' buffer
- * and return the 'var' pointer. Nothing is done to the arguments if
- * len == 0 or var is NULL, var is still returned. On overflow, the
- * first char will be set to '\0'.
- */
-static char *ai_devpathvar(struct si_pub *sih, char *var, int len,
- const char *name)
-{
- uint path_len;
-
- if (!var || len <= 0)
- return var;
-
- if (ai_devpath(sih, var, len) == 0) {
- path_len = strlen(var);
-
- if (strlen(name) + 1 > (uint) (len - path_len))
- var[0] = '\0';
- else
- strncpy(var + path_len, name, len - path_len - 1);
- }
-
- return var;
-}
-
-/* return true if PCIE capability exists in the pci config space */
-static bool ai_ispcie(struct si_info *sii)
-{
- u8 cap_ptr;
-
- if (sii->pub.bustype != PCI_BUS)
- return false;
-
- cap_ptr =
- pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL,
- NULL);
- if (!cap_ptr)
- return false;
-
- return true;
-}
-
-bool ai_pci_war16165(struct si_pub *sih)
-{
- struct si_info *sii;
-
- sii = SI_INFO(sih);
-
- return PCI(sii) && (sih->buscorerev <= 10);
-}
-
void ai_pci_up(struct si_pub *sih)
{
struct si_info *sii;
- sii = SI_INFO(sih);
-
- /* if not pci bus, we're done */
- if (sih->bustype != PCI_BUS)
- return;
+ sii = (struct si_info *)sih;
if (PCI_FORCEHT(sii))
_ai_clkctl_cc(sii, CLK_FAST);
@@ -2049,7 +1869,7 @@ void ai_pci_sleep(struct si_pub *sih)
{
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
pcicore_sleep(sii->pch);
}
@@ -2059,11 +1879,7 @@ void ai_pci_down(struct si_pub *sih)
{
struct si_info *sii;
- sii = SI_INFO(sih);
-
- /* if not pci bus, we're done */
- if (sih->bustype != PCI_BUS)
- return;
+ sii = (struct si_info *)sih;
/* release FORCEHT since chip is going to "down" state */
if (PCI_FORCEHT(sii))
@@ -2079,14 +1895,11 @@ void ai_pci_down(struct si_pub *sih)
void ai_pci_setup(struct si_pub *sih, uint coremask)
{
struct si_info *sii;
- void *regs = NULL;
+ struct sbpciregs __iomem *regs = NULL;
u32 siflag = 0, w;
uint idx = 0;
- sii = SI_INFO(sih);
-
- if (sii->pub.bustype != PCI_BUS)
- return;
+ sii = (struct si_info *)sih;
if (PCI(sii)) {
/* get current core index */
@@ -2128,9 +1941,8 @@ void ai_pci_setup(struct si_pub *sih, uint coremask)
int ai_pci_fixcfg(struct si_pub *sih)
{
uint origidx;
- void *regs = NULL;
-
- struct si_info *sii = SI_INFO(sih);
+ void __iomem *regs = NULL;
+ struct si_info *sii = (struct si_info *)sih;
/* Fixup PI in SROM shadow area to enable the correct PCI core access */
/* save the current index */
@@ -2138,7 +1950,11 @@ int ai_pci_fixcfg(struct si_pub *sih)
/* check 'pi' is correct and fix it if not */
regs = ai_setcore(&sii->pub, sii->pub.buscoretype, 0);
- pcicore_fixcfg(sii->pch, regs);
+ if (sii->pub.buscoretype == PCIE_CORE_ID)
+ pcicore_fixcfg_pcie(sii->pch,
+ (struct sbpcieregs __iomem *)regs);
+ else if (sii->pub.buscoretype == PCI_CORE_ID)
+ pcicore_fixcfg_pci(sii->pch, (struct sbpciregs __iomem *)regs);
/* restore the original index */
ai_setcoreidx(&sii->pub, origidx);
@@ -2152,47 +1968,34 @@ u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority)
{
uint regoff;
- regoff = 0;
-
- /* gpios could be shared on router platforms
- * ignore reservation if it's high priority (e.g., test apps)
- */
- if ((priority != GPIO_HI_PRIORITY) &&
- (sih->bustype == SI_BUS) && (val || mask)) {
- mask = priority ? (ai_gpioreservation & mask) :
- ((ai_gpioreservation | mask) & ~(ai_gpioreservation));
- val &= mask;
- }
-
- regoff = offsetof(chipcregs_t, gpiocontrol);
+ regoff = offsetof(struct chipcregs, gpiocontrol);
return ai_corereg(sih, SI_CC_IDX, regoff, mask, val);
}
void ai_chipcontrl_epa4331(struct si_pub *sih, bool on)
{
struct si_info *sii;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
u32 val;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
origidx = ai_coreidx(sih);
- cc = (chipcregs_t *) ai_setcore(sih, CC_CORE_ID, 0);
+ cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0);
val = R_REG(&cc->chipcontrol);
if (on) {
- if (sih->chippkg == 9 || sih->chippkg == 0xb) {
+ if (sih->chippkg == 9 || sih->chippkg == 0xb)
/* Ext PA Controls for 4331 12x9 Package */
W_REG(&cc->chipcontrol, val |
- (CCTRL4331_EXTPA_EN |
- CCTRL4331_EXTPA_ON_GPIO2_5));
- } else {
+ CCTRL4331_EXTPA_EN |
+ CCTRL4331_EXTPA_ON_GPIO2_5);
+ else
/* Ext PA Controls for 4331 12x12 Package */
W_REG(&cc->chipcontrol,
- val | (CCTRL4331_EXTPA_EN));
- }
+ val | CCTRL4331_EXTPA_EN);
} else {
val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
W_REG(&cc->chipcontrol, val);
@@ -2205,13 +2008,13 @@ void ai_chipcontrl_epa4331(struct si_pub *sih, bool on)
void ai_epa_4313war(struct si_pub *sih)
{
struct si_info *sii;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
origidx = ai_coreidx(sih);
- cc = (chipcregs_t *) ai_setcore(sih, CC_CORE_ID, 0);
+ cc = ai_setcore(sih, CC_CORE_ID, 0);
/* EPA Fix */
W_REG(&cc->gpiocontrol,
@@ -2226,15 +2029,12 @@ bool ai_deviceremoved(struct si_pub *sih)
u32 w;
struct si_info *sii;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
+
+ pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w);
+ if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM)
+ return true;
- switch (sih->bustype) {
- case PCI_BUS:
- pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w);
- if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM)
- return true;
- break;
- }
return false;
}
@@ -2243,13 +2043,13 @@ bool ai_is_sprom_available(struct si_pub *sih)
if (sih->ccrev >= 31) {
struct si_info *sii;
uint origidx;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
u32 sromctrl;
if ((sih->cccaps & CC_CAP_SROM) == 0)
return false;
- sii = SI_INFO(sih);
+ sii = (struct si_info *)sih;
origidx = sii->curidx;
cc = ai_setcoreidx(sih, SI_CC_IDX);
sromctrl = R_REG(&cc->sromcontrol);
diff --git a/drivers/staging/brcm80211/brcmsmac/aiutils.h b/drivers/staging/brcm80211/brcmsmac/aiutils.h
index e245c278bebc..106a7424a7cd 100644
--- a/drivers/staging/brcm80211/brcmsmac/aiutils.h
+++ b/drivers/staging/brcm80211/brcmsmac/aiutils.h
@@ -23,26 +23,6 @@
* SOC Interconnect Address Map.
* All regions may not exist on all chips.
*/
-/* Physical SDRAM */
-#define SI_SDRAM_BASE 0x00000000
-/* Host Mode sb2pcitranslation0 (64 MB) */
-#define SI_PCI_MEM 0x08000000
-#define SI_PCI_MEM_SZ (64 * 1024 * 1024)
-/* Host Mode sb2pcitranslation1 (64 MB) */
-#define SI_PCI_CFG 0x0c000000
-/* Byteswapped Physical SDRAM */
-#define SI_SDRAM_SWAPPED 0x10000000
-/* Region 2 for sdram (512 MB) */
-#define SI_SDRAM_R2 0x80000000
-
-#ifdef SI_ENUM_BASE_VARIABLE
-#define SI_ENUM_BASE (sii->pub.si_enum_base)
-#else
-#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
-#endif /* SI_ENUM_BASE_VARIABLE */
-
-/* Wrapper space base */
-#define SI_WRAP_BASE 0x18100000
/* each core gets 4Kbytes for registers */
#define SI_CORE_SIZE 0x1000
/*
@@ -52,39 +32,9 @@
*/
#define SI_MAXCORES 16
-/* On-chip RAM on chips that also have DDR */
-#define SI_FASTRAM 0x19000000
-#define SI_FASTRAM_SWAPPED 0x19800000
-
-/* Flash Region 2 (region 1 shadowed here) */
-#define SI_FLASH2 0x1c000000
-/* Size of Flash Region 2 */
-#define SI_FLASH2_SZ 0x02000000
-/* ARM Cortex-M3 ROM */
-#define SI_ARMCM3_ROM 0x1e000000
-/* MIPS Flash Region 1 */
-#define SI_FLASH1 0x1fc00000
-/* MIPS Size of Flash Region 1 */
-#define SI_FLASH1_SZ 0x00400000
-/* ARM7TDMI-S ROM */
-#define SI_ARM7S_ROM 0x20000000
-/* ARM Cortex-M3 SRAM Region 2 */
-#define SI_ARMCM3_SRAM2 0x60000000
-/* ARM7TDMI-S SRAM Region 2 */
-#define SI_ARM7S_SRAM2 0x80000000
-/* ARM Flash Region 1 */
-#define SI_ARM_FLASH1 0xffff0000
-/* ARM Size of Flash Region 1 */
-#define SI_ARM_FLASH1_SZ 0x00010000
-
-/* Client Mode sb2pcitranslation2 (1 GB) */
-#define SI_PCI_DMA 0x40000000
-/* Client Mode sb2pcitranslation2 (1 GB) */
-#define SI_PCI_DMA2 0x80000000
/* Client Mode sb2pcitranslation2 size in bytes */
#define SI_PCI_DMA_SZ 0x40000000
-/* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */
-#define SI_PCIE_DMA_L32 0x00000000
+
/* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
#define SI_PCIE_DMA_H32 0x80000000
@@ -203,18 +153,6 @@
/* Minumum amount of flash we support */
#define FLASH_MIN 0x00020000 /* Minimum flash size */
-/* A boot/binary may have an embedded block that describes its size */
-#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */
-#define BISZ_MAGIC 0x4249535a /* Marked with value: 'BISZ' */
-#define BISZ_MAGIC_IDX 0 /* Word 0: magic */
-#define BISZ_TXTST_IDX 1 /* 1: text start */
-#define BISZ_TXTEND_IDX 2 /* 2: text end */
-#define BISZ_DATAST_IDX 3 /* 3: data start */
-#define BISZ_DATAEND_IDX 4 /* 4: data end */
-#define BISZ_BSSST_IDX 5 /* 5: bss start */
-#define BISZ_BSSEND_IDX 6 /* 6: bss end */
-#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */
-
#define CC_SROM_OTP 0x800 /* SROM/OTP address space */
/* gpiotimerval */
@@ -224,93 +162,15 @@
#define CLKD_OTP 0x000f0000
#define CLKD_OTP_SHIFT 16
-/* When Srom support present, fields in sromcontrol */
-#define SRC_START 0x80000000
-#define SRC_BUSY 0x80000000
-#define SRC_OPCODE 0x60000000
-#define SRC_OP_READ 0x00000000
-#define SRC_OP_WRITE 0x20000000
-#define SRC_OP_WRDIS 0x40000000
-#define SRC_OP_WREN 0x60000000
-#define SRC_OTPSEL 0x00000010
-#define SRC_LOCK 0x00000008
-#define SRC_SIZE_MASK 0x00000006
-#define SRC_SIZE_1K 0x00000000
-#define SRC_SIZE_4K 0x00000002
-#define SRC_SIZE_16K 0x00000004
-#define SRC_SIZE_SHIFT 1
-#define SRC_PRESENT 0x00000001
-
-/* 4330 chip-specific ChipStatus register bits */
-#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */
-#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */
-#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */
-#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */
-#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */
-#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */
-#define CST4330_OTP_PRESENT 0x00000010
-#define CST4330_LPO_AUTODET_EN 0x00000020
-#define CST4330_ARMREMAP_0 0x00000040
-#define CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */
-#define CST4330_ILPDIV_EN 0x00000100
-#define CST4330_LPO_SEL 0x00000200
-#define CST4330_RES_INIT_MODE_SHIFT 10
-#define CST4330_RES_INIT_MODE_MASK 0x00000c00
-#define CST4330_CBUCK_MODE_SHIFT 12
-#define CST4330_CBUCK_MODE_MASK 0x00003000
-#define CST4330_CBUCK_POWER_OK 0x00004000
-#define CST4330_BB_PLL_LOCKED 0x00008000
-
/* Package IDs */
-#define BCM4329_289PIN_PKG_ID 0 /* 4329 289-pin package id */
-#define BCM4329_182PIN_PKG_ID 1 /* 4329N 182-pin package id */
#define BCM4717_PKG_ID 9 /* 4717 package id */
#define BCM4718_PKG_ID 10 /* 4718 package id */
-#define HDLSIM_PKG_ID 14 /* HDL simulator package id */
-#define HWSIM_PKG_ID 15 /* Hardware simulator package id */
#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */
/* these are router chips */
#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */
#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */
#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
-#define BCM5356_CHIP_ID 0x5356 /* 5356 chipcommon chipid */
-#define BCM5357_CHIP_ID 0x5357 /* 5357 chipcommon chipid */
-
-
-#define SI_INFO(sih) ((struct si_info *)sih)
-
-#define GOODCOREADDR(x, b) \
- (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \
- IS_ALIGNED((x), SI_CORE_SIZE))
-#define GOODREGS(regs) \
- ((regs) != NULL && IS_ALIGNED((unsigned long)(regs), SI_CORE_SIZE))
-#define BADCOREADDR 0
-#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES)
-#define NOREV -1 /* Invalid rev */
-
-/* Newer chips can access PCI/PCIE and CC core without requiring to change
- * PCI BAR0 WIN
- */
-#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \
- (((si)->pub.buscoretype == PCI_CORE_ID) && \
- (si)->pub.buscorerev >= 13))
-
-#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET))
-#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET))
-
-/*
- * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts
- * before after core switching to avoid invalid register accesss inside ISR.
- */
-#define INTR_OFF(si, intr_val) \
- if ((si)->intrsoff_fn && \
- (si)->coreid[(si)->curidx] == (si)->dev_coreid) \
- intr_val = (*(si)->intrsoff_fn)((si)->intr_arg)
-#define INTR_RESTORE(si, intr_val) \
- if ((si)->intrsrestore_fn && \
- (si)->coreid[(si)->curidx] == (si)->dev_coreid) \
- (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val)
/* dynamic clock control defines */
#define LPOMINFREQ 25000 /* low power oscillator min */
@@ -323,60 +183,6 @@
#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
-#define PCI(si) (((si)->pub.bustype == PCI_BUS) && \
- ((si)->pub.buscoretype == PCI_CORE_ID))
-#define PCIE(si) (((si)->pub.bustype == PCI_BUS) && \
- ((si)->pub.buscoretype == PCIE_CORE_ID))
-#define PCI_FORCEHT(si) \
- (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID))
-
-/* GPIO Based LED powersave defines */
-#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
-#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
-
-#ifndef DEFAULT_GPIOTIMERVAL
-#define DEFAULT_GPIOTIMERVAL \
- ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
-#endif
-
-/*
- * Data structure to export all chip specific common variables
- * public (read-only) portion of aiutils handle returned by si_attach()
- */
-struct si_pub {
- uint bustype; /* SI_BUS, PCI_BUS */
- uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */
- uint buscorerev; /* buscore rev */
- uint buscoreidx; /* buscore index */
- int ccrev; /* chip common core rev */
- u32 cccaps; /* chip common capabilities */
- u32 cccaps_ext; /* chip common capabilities extension */
- int pmurev; /* pmu core rev */
- u32 pmucaps; /* pmu capabilities */
- uint boardtype; /* board type */
- uint boardvendor; /* board vendor */
- uint boardflags; /* board flags */
- uint boardflags2; /* board flags2 */
- uint chip; /* chip number */
- uint chiprev; /* chip revision */
- uint chippkg; /* chip package option */
- u32 chipst; /* chip status */
- bool issim; /* chip is in simulation or emulation */
- uint socirev; /* SOC interconnect rev */
- bool pci_pr32414;
-
-};
-
-/*
- * Many of the routines below take an 'sih' handle as their first arg.
- * Allocate this by calling si_attach(). Free it by calling si_detach().
- * At any one time, the sih is logically focused on one particular si core
- * (the "current core").
- * Use si_setcore() or si_setcoreidx() to change the association to another core
- */
-
-#define BADIDX (SI_MAXCORES + 1)
-
/* clkctl xtal what flags */
#define XTAL 0x1 /* primary crystal oscillator (2050) */
#define PLL 0x2 /* main chip pll */
@@ -409,49 +215,39 @@ struct si_pub {
#define SI_PCIDOWN 2
#define SI_PCIUP 3
-/* PMU clock/power control */
-#if defined(BCMPMUCTL)
-#define PMUCTL_ENAB(sih) (BCMPMUCTL)
-#else
-#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU)
-#endif
-
-/* chipcommon clock/power control (exclusive with PMU's) */
-#if defined(BCMPMUCTL) && BCMPMUCTL
-#define CCCTL_ENAB(sih) (0)
-#define CCPLL_ENAB(sih) (0)
-#else
-#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL)
-#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK)
-#endif
-
-typedef void (*gpio_handler_t) (u32 stat, void *arg);
-
-/* External PA enable mask */
-#define GPIO_CTRL_EPA_EN_MASK 0x40
-
-#define SI_ERROR(args)
-
-#ifdef BCMDBG
-#define SI_MSG(args) printk args
-#else
-#define SI_MSG(args)
-#endif /* BCMDBG */
-
-/* Define SI_VMSG to printf for verbose debugging, but don't check it in */
-#define SI_VMSG(args)
+/*
+ * Data structure to export all chip specific common variables
+ * public (read-only) portion of aiutils handle returned by si_attach()
+ */
+struct si_pub {
+ uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */
+ uint buscorerev; /* buscore rev */
+ uint buscoreidx; /* buscore index */
+ int ccrev; /* chip common core rev */
+ u32 cccaps; /* chip common capabilities */
+ u32 cccaps_ext; /* chip common capabilities extension */
+ int pmurev; /* pmu core rev */
+ u32 pmucaps; /* pmu capabilities */
+ uint boardtype; /* board type */
+ uint boardvendor; /* board vendor */
+ uint boardflags; /* board flags */
+ uint boardflags2; /* board flags2 */
+ uint chip; /* chip number */
+ uint chiprev; /* chip revision */
+ uint chippkg; /* chip package option */
+ u32 chipst; /* chip status */
+ bool issim; /* chip is in simulation or emulation */
+ uint socirev; /* SOC interconnect rev */
+ bool pci_pr32414;
-#define IS_SIM(chippkg) \
- ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
+};
-typedef u32(*si_intrsoff_t) (void *intr_arg);
-typedef void (*si_intrsrestore_t) (void *intr_arg, u32 arg);
-typedef bool(*si_intrsenabled_t) (void *intr_arg);
+struct pci_dev;
struct gpioh_item {
void *arg;
bool level;
- gpio_handler_t handler;
+ void (*handler) (u32 stat, void *arg);
u32 event;
struct gpioh_item *next;
};
@@ -459,20 +255,21 @@ struct gpioh_item {
/* misc si info needed by some of the routines */
struct si_info {
struct si_pub pub; /* back plane public state (must be first) */
- void *pbus; /* handle to bus (pci/sdio/..) */
+ struct pci_dev *pbus; /* handle to pci bus */
uint dev_coreid; /* the core provides driver functions */
void *intr_arg; /* interrupt callback function arg */
- si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */
- si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */
- si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */
+ u32 (*intrsoff_fn) (void *intr_arg); /* turns chip interrupts off */
+ /* restore chip interrupts */
+ void (*intrsrestore_fn) (void *intr_arg, u32 arg);
+ /* check if interrupts are enabled */
+ bool (*intrsenabled_fn) (void *intr_arg);
- void *pch; /* PCI/E core handle */
+ struct pcicore_info *pch; /* PCI/E core handle */
- char *vars;
- uint varsz;
+ struct list_head var_list; /* list of srom variables */
- void *curmap; /* current regs va */
- void *regs[SI_MAXCORES]; /* other regs va */
+ void __iomem *curmap; /* current regs va */
+ void __iomem *regs[SI_MAXCORES]; /* other regs va */
uint curidx; /* current core index */
uint numcores; /* # discovered cores */
@@ -492,16 +289,22 @@ struct si_info {
u32 oob_router; /* oob router registers for axi */
};
-/* AMBA Interconnect exported externs */
-extern void ai_scan(struct si_pub *sih, void *regs);
+/*
+ * Many of the routines below take an 'sih' handle as their first arg.
+ * Allocate this by calling si_attach(). Free it by calling si_detach().
+ * At any one time, the sih is logically focused on one particular si core
+ * (the "current core").
+ * Use si_setcore() or si_setcoreidx() to change the association to another core
+ */
+
+/* AMBA Interconnect exported externs */
extern uint ai_flag(struct si_pub *sih);
extern void ai_setint(struct si_pub *sih, int siflag);
extern uint ai_coreidx(struct si_pub *sih);
extern uint ai_corevendor(struct si_pub *sih);
extern uint ai_corerev(struct si_pub *sih);
extern bool ai_iscoreup(struct si_pub *sih);
-extern void *ai_setcoreidx(struct si_pub *sih, uint coreidx);
extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val);
extern void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val);
extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val);
@@ -515,12 +318,8 @@ extern u32 ai_addrspacesize(struct si_pub *sih, uint asidx);
extern void ai_write_wrap_reg(struct si_pub *sih, u32 offset, u32 val);
/* === exported functions === */
-extern struct si_pub *ai_attach(void *regs, uint bustype,
- void *sdh, char **vars, uint *varsz);
-
+extern struct si_pub *ai_attach(void __iomem *regs, struct pci_dev *sdh);
extern void ai_detach(struct si_pub *sih);
-extern bool ai_pci_war16165(struct si_pub *sih);
-
extern uint ai_coreid(struct si_pub *sih);
extern uint ai_corerev(struct si_pub *sih);
extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask,
@@ -530,10 +329,10 @@ extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val);
extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val);
extern bool ai_iscoreup(struct si_pub *sih);
extern uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit);
-extern void *ai_setcoreidx(struct si_pub *sih, uint coreidx);
-extern void *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit);
-extern void *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx,
- uint *intr_val);
+extern void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx);
+extern void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit);
+extern void __iomem *ai_switch_core(struct si_pub *sih, uint coreid,
+ uint *origidx, uint *intr_val);
extern void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val);
extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits);
extern void ai_core_disable(struct si_pub *sih, u32 bits);
@@ -566,9 +365,6 @@ extern bool ai_is_sprom_available(struct si_pub *sih);
* Return 0 on success, nonzero otherwise.
*/
extern int ai_devpath(struct si_pub *sih, char *path, int size);
-/* Read variable with prepending the devpath to the name */
-extern char *ai_getdevpathvar(struct si_pub *sih, const char *name);
-extern int ai_getdevpathintvar(struct si_pub *sih, const char *name);
extern void ai_pci_sleep(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih);
@@ -579,6 +375,4 @@ extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on);
/* Enable Ex-PA for 4313 */
extern void ai_epa_4313war(struct si_pub *sih);
-char *ai_getnvramflvar(struct si_pub *sih, const char *name);
-
#endif /* _BRCM_AIUTILS_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/alloc.c b/drivers/staging/brcm80211/brcmsmac/alloc.c
deleted file mode 100644
index 7f8dd7b396bf..000000000000
--- a/drivers/staging/brcm80211/brcmsmac/alloc.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <brcmu_utils.h>
-#include "types.h"
-#include "pub.h"
-#include "main.h"
-#include "alloc.h"
-
-static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit);
-static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg);
-static struct brcms_pub *brcms_c_pub_malloc(uint unit,
- uint *err, uint devid);
-static void brcms_c_pub_mfree(struct brcms_pub *pub);
-static void brcms_c_tunables_init(struct brcms_tunables *tunables, uint devid);
-
-static void brcms_c_tunables_init(struct brcms_tunables *tunables, uint devid)
-{
- tunables->ntxd = NTXD;
- tunables->nrxd = NRXD;
- tunables->rxbufsz = RXBUFSZ;
- tunables->nrxbufpost = NRXBUFPOST;
- tunables->maxscb = MAXSCB;
- tunables->ampdunummpdu = AMPDU_NUM_MPDU;
- tunables->maxpktcb = MAXPKTCB;
- tunables->maxucodebss = BRCMS_MAX_UCODE_BSS;
- tunables->maxucodebss4 = BRCMS_MAX_UCODE_BSS4;
- tunables->maxbss = MAXBSS;
- tunables->datahiwat = BRCMS_DATAHIWAT;
- tunables->ampdudatahiwat = BRCMS_AMPDUDATAHIWAT;
- tunables->rxbnd = RXBND;
- tunables->txsbnd = TXSBND;
-}
-
-static struct brcms_pub *brcms_c_pub_malloc(uint unit, uint *err, uint devid)
-{
- struct brcms_pub *pub;
-
- pub = kzalloc(sizeof(struct brcms_pub), GFP_ATOMIC);
- if (pub == NULL) {
- *err = 1001;
- goto fail;
- }
-
- pub->tunables = kzalloc(sizeof(struct brcms_tunables), GFP_ATOMIC);
- if (pub->tunables == NULL) {
- *err = 1028;
- goto fail;
- }
-
- /* need to init the tunables now */
- brcms_c_tunables_init(pub->tunables, devid);
-
- pub->multicast = kzalloc(ETH_ALEN * MAXMULTILIST, GFP_ATOMIC);
- if (pub->multicast == NULL) {
- *err = 1003;
- goto fail;
- }
-
- return pub;
-
- fail:
- brcms_c_pub_mfree(pub);
- return NULL;
-}
-
-static void brcms_c_pub_mfree(struct brcms_pub *pub)
-{
- if (pub == NULL)
- return;
-
- kfree(pub->multicast);
- kfree(pub->tunables);
- kfree(pub);
-}
-
-static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)
-{
- struct brcms_bss_cfg *cfg;
-
- cfg = kzalloc(sizeof(struct brcms_bss_cfg), GFP_ATOMIC);
- if (cfg == NULL)
- goto fail;
-
- cfg->current_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
- if (cfg->current_bss == NULL)
- goto fail;
-
- return cfg;
-
- fail:
- brcms_c_bsscfg_mfree(cfg);
- return NULL;
-}
-
-static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
-{
- if (cfg == NULL)
- return;
-
- kfree(cfg->maclist);
- kfree(cfg->current_bss);
- kfree(cfg);
-}
-
-static void brcms_c_bsscfg_ID_assign(struct brcms_c_info *wlc,
- struct brcms_bss_cfg *bsscfg)
-{
- bsscfg->ID = wlc->next_bsscfg_ID;
- wlc->next_bsscfg_ID++;
-}
-
-/*
- * The common driver entry routine. Error codes should be unique
- */
-struct brcms_c_info *brcms_c_attach_malloc(uint unit, uint *err, uint devid)
-{
- struct brcms_c_info *wlc;
-
- wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC);
- if (wlc == NULL) {
- *err = 1002;
- goto fail;
- }
-
- /* allocate struct brcms_c_pub state structure */
- wlc->pub = brcms_c_pub_malloc(unit, err, devid);
- if (wlc->pub == NULL) {
- *err = 1003;
- goto fail;
- }
- wlc->pub->wlc = wlc;
-
- /* allocate struct brcms_hardware state structure */
-
- wlc->hw = kzalloc(sizeof(struct brcms_hardware), GFP_ATOMIC);
- if (wlc->hw == NULL) {
- *err = 1005;
- goto fail;
- }
- wlc->hw->wlc = wlc;
-
- wlc->hw->bandstate[0] =
- kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC);
- if (wlc->hw->bandstate[0] == NULL) {
- *err = 1006;
- goto fail;
- } else {
- int i;
-
- for (i = 1; i < MAXBANDS; i++) {
- wlc->hw->bandstate[i] = (struct brcms_hw_band *)
- ((unsigned long)wlc->hw->bandstate[0] +
- (sizeof(struct brcms_hw_band) * i));
- }
- }
-
- wlc->modulecb =
- kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC);
- if (wlc->modulecb == NULL) {
- *err = 1009;
- goto fail;
- }
-
- wlc->default_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
- if (wlc->default_bss == NULL) {
- *err = 1010;
- goto fail;
- }
-
- wlc->cfg = brcms_c_bsscfg_malloc(unit);
- if (wlc->cfg == NULL) {
- *err = 1011;
- goto fail;
- }
- brcms_c_bsscfg_ID_assign(wlc, wlc->cfg);
-
- wlc->wsec_def_keys[0] =
- kzalloc(sizeof(struct wsec_key) * BRCMS_DEFAULT_KEYS,
- GFP_ATOMIC);
- if (wlc->wsec_def_keys[0] == NULL) {
- *err = 1015;
- goto fail;
- } else {
- int i;
- for (i = 1; i < BRCMS_DEFAULT_KEYS; i++) {
- wlc->wsec_def_keys[i] = (struct wsec_key *)
- ((unsigned long)wlc->wsec_def_keys[0] +
- (sizeof(struct wsec_key) * i));
- }
- }
-
- wlc->protection = kzalloc(sizeof(struct brcms_protection),
- GFP_ATOMIC);
- if (wlc->protection == NULL) {
- *err = 1016;
- goto fail;
- }
-
- wlc->stf = kzalloc(sizeof(struct brcms_stf), GFP_ATOMIC);
- if (wlc->stf == NULL) {
- *err = 1017;
- goto fail;
- }
-
- wlc->bandstate[0] =
- kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC);
- if (wlc->bandstate[0] == NULL) {
- *err = 1025;
- goto fail;
- } else {
- int i;
-
- for (i = 1; i < MAXBANDS; i++) {
- wlc->bandstate[i] = (struct brcms_band *)
- ((unsigned long)wlc->bandstate[0]
- + (sizeof(struct brcms_band)*i));
- }
- }
-
- wlc->corestate = kzalloc(sizeof(struct brcms_core), GFP_ATOMIC);
- if (wlc->corestate == NULL) {
- *err = 1026;
- goto fail;
- }
-
- wlc->corestate->macstat_snapshot =
- kzalloc(sizeof(struct macstat), GFP_ATOMIC);
- if (wlc->corestate->macstat_snapshot == NULL) {
- *err = 1027;
- goto fail;
- }
-
- return wlc;
-
- fail:
- brcms_c_detach_mfree(wlc);
- return NULL;
-}
-
-void brcms_c_detach_mfree(struct brcms_c_info *wlc)
-{
- if (wlc == NULL)
- return;
-
- brcms_c_bsscfg_mfree(wlc->cfg);
- brcms_c_pub_mfree(wlc->pub);
- kfree(wlc->modulecb);
- kfree(wlc->default_bss);
- kfree(wlc->wsec_def_keys[0]);
- kfree(wlc->protection);
- kfree(wlc->stf);
- kfree(wlc->bandstate[0]);
- kfree(wlc->corestate->macstat_snapshot);
- kfree(wlc->corestate);
- kfree(wlc->hw->bandstate[0]);
- kfree(wlc->hw);
-
- /* free the wlc */
- kfree(wlc);
- wlc = NULL;
-}
diff --git a/drivers/staging/brcm80211/brcmsmac/ampdu.c b/drivers/staging/brcm80211/brcmsmac/ampdu.c
index fcaf61e3b134..7f27dbdb6b60 100644
--- a/drivers/staging/brcm80211/brcmsmac/ampdu.c
+++ b/drivers/staging/brcm80211/brcmsmac/ampdu.c
@@ -22,19 +22,32 @@
#include "main.h"
#include "ampdu.h"
-#define AMPDU_MAX_MPDU 32 /* max number of mpdus in an ampdu */
-#define AMPDU_NUM_MPDU_LEGACY 16 /* max number of mpdus in an ampdu to a legacy */
-#define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
-#define AMPDU_TX_BA_DEF_WSIZE 64 /* default Tx ba window size (in pdu) */
-#define AMPDU_RX_BA_DEF_WSIZE 64 /* max Rx ba window size (in pdu) */
-#define AMPDU_RX_BA_MAX_WSIZE 64 /* default Rx ba window size (in pdu) */
-#define AMPDU_MAX_DUR 5 /* max dur of tx ampdu (in msec) */
-#define AMPDU_DEF_RETRY_LIMIT 5 /* default tx retry limit */
-#define AMPDU_DEF_RR_RETRY_LIMIT 2 /* default tx retry limit at reg rate */
-#define AMPDU_DEF_TXPKT_WEIGHT 2 /* default weight of ampdu in txfifo */
-#define AMPDU_DEF_FFPLD_RSVD 2048 /* default ffpld reserved bytes */
-#define AMPDU_INI_FREE 10 /* # of inis to be freed on detach */
-#define AMPDU_SCB_MAX_RELEASE 20 /* max # of mpdus released at a time */
+/* max number of mpdus in an ampdu */
+#define AMPDU_MAX_MPDU 32
+/* max number of mpdus in an ampdu to a legacy */
+#define AMPDU_NUM_MPDU_LEGACY 16
+/* max Tx ba window size (in pdu) */
+#define AMPDU_TX_BA_MAX_WSIZE 64
+/* default Tx ba window size (in pdu) */
+#define AMPDU_TX_BA_DEF_WSIZE 64
+/* default Rx ba window size (in pdu) */
+#define AMPDU_RX_BA_DEF_WSIZE 64
+/* max Rx ba window size (in pdu) */
+#define AMPDU_RX_BA_MAX_WSIZE 64
+/* max dur of tx ampdu (in msec) */
+#define AMPDU_MAX_DUR 5
+/* default tx retry limit */
+#define AMPDU_DEF_RETRY_LIMIT 5
+/* default tx retry limit at reg rate */
+#define AMPDU_DEF_RR_RETRY_LIMIT 2
+/* default weight of ampdu in txfifo */
+#define AMPDU_DEF_TXPKT_WEIGHT 2
+/* default ffpld reserved bytes */
+#define AMPDU_DEF_FFPLD_RSVD 2048
+/* # of inis to be freed on detach */
+#define AMPDU_INI_FREE 10
+/* max # of mpdus released at a time */
+#define AMPDU_SCB_MAX_RELEASE 20
#define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */
#define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu
@@ -47,6 +60,11 @@
* accumulate between resets.
*/
+#define AMPDU_DELIMITER_LEN 4
+
+/* max allowed number of mpdus in an ampdu (2 streams) */
+#define AMPDU_NUM_MPDU 16
+
#define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE)
/* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */
@@ -54,49 +72,77 @@
AMPDU_DELIMITER_LEN + 3\
+ DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN)
+/* modulo add/sub, bound = 2^k */
+#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
+#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
+
/* structure to hold tx fifo information and pre-loading state
* counters specific to tx underflows of ampdus
* some counters might be redundant with the ones in wlc or ampdu structures.
* This allows to maintain a specific state independently of
* how often and/or when the wlc counters are updated.
+ *
+ * ampdu_pld_size: number of bytes to be pre-loaded
+ * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu
+ * prev_txfunfl: num of underflows last read from the HW macstats counter
+ * accum_txfunfl: num of underflows since we modified pld params
+ * accum_txampdu: num of tx ampdu since we modified pld params
+ * prev_txampdu: previous reading of tx ampdu
+ * dmaxferrate: estimated dma avg xfer rate in kbits/sec
*/
struct brcms_fifo_info {
- u16 ampdu_pld_size; /* number of bytes to be pre-loaded */
- u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; /* per-mcs max # of mpdus in an ampdu */
- u16 prev_txfunfl; /* num of underflows last read from the HW macstats counter */
- u32 accum_txfunfl; /* num of underflows since we modified pld params */
- u32 accum_txampdu; /* num of tx ampdu since we modified pld params */
- u32 prev_txampdu; /* previous reading of tx ampdu */
- u32 dmaxferrate; /* estimated dma avg xfer rate in kbits/sec */
+ u16 ampdu_pld_size;
+ u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1];
+ u16 prev_txfunfl;
+ u32 accum_txfunfl;
+ u32 accum_txampdu;
+ u32 prev_txampdu;
+ u32 dmaxferrate;
};
-/* AMPDU module specific state */
+/* AMPDU module specific state
+ *
+ * wlc: pointer to main wlc structure
+ * scb_handle: scb cubby handle to retrieve data from scb
+ * ini_enable: per-tid initiator enable/disable of ampdu
+ * ba_tx_wsize: Tx ba window size (in pdu)
+ * ba_rx_wsize: Rx ba window size (in pdu)
+ * retry_limit: mpdu transmit retry limit
+ * rr_retry_limit: mpdu transmit retry limit at regular rate
+ * retry_limit_tid: per-tid mpdu transmit retry limit
+ * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate
+ * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
+ * max_pdu: max pdus allowed in ampdu
+ * dur: max duration of an ampdu (in msec)
+ * txpkt_weight: weight of ampdu in txfifo; reduces rate lag
+ * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
+ * ffpld_rsvd: number of bytes to reserve for preload
+ * max_txlen: max size of ampdu per mcs, bw and sgi
+ * mfbr: enable multiple fallback rate
+ * tx_max_funl: underflows should be kept such that
+ * (tx_max_funfl*underflows) < tx frames
+ * fifo_tb: table of fifo infos
+ */
struct ampdu_info {
- struct brcms_c_info *wlc; /* pointer to main wlc structure */
- int scb_handle; /* scb cubby handle to retrieve data from scb */
- u8 ini_enable[AMPDU_MAX_SCB_TID]; /* per-tid initiator enable/disable of ampdu */
- u8 ba_tx_wsize; /* Tx ba window size (in pdu) */
- u8 ba_rx_wsize; /* Rx ba window size (in pdu) */
- u8 retry_limit; /* mpdu transmit retry limit */
- u8 rr_retry_limit; /* mpdu transmit retry limit at regular rate */
- u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; /* per-tid mpdu transmit retry limit */
- /* per-tid mpdu transmit retry limit at regular rate */
+ struct brcms_c_info *wlc;
+ int scb_handle;
+ u8 ini_enable[AMPDU_MAX_SCB_TID];
+ u8 ba_tx_wsize;
+ u8 ba_rx_wsize;
+ u8 retry_limit;
+ u8 rr_retry_limit;
+ u8 retry_limit_tid[AMPDU_MAX_SCB_TID];
u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID];
- u8 mpdu_density; /* min mpdu spacing (0-7) ==> 2^(x-1)/8 usec */
- s8 max_pdu; /* max pdus allowed in ampdu */
- u8 dur; /* max duration of an ampdu (in msec) */
- u8 txpkt_weight; /* weight of ampdu in txfifo; reduces rate lag */
- u8 rx_factor; /* maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes */
- u32 ffpld_rsvd; /* number of bytes to reserve for preload */
- u32 max_txlen[MCS_TABLE_SIZE][2][2]; /* max size of ampdu per mcs, bw and sgi */
- void *ini_free[AMPDU_INI_FREE]; /* array of ini's to be freed on detach */
- bool mfbr; /* enable multiple fallback rate */
- u32 tx_max_funl; /* underflows should be kept such that
- * (tx_max_funfl*underflows) < tx frames
- */
- /* table of fifo infos */
+ u8 mpdu_density;
+ s8 max_pdu;
+ u8 dur;
+ u8 txpkt_weight;
+ u8 rx_factor;
+ u32 ffpld_rsvd;
+ u32 max_txlen[MCS_TABLE_SIZE][2][2];
+ bool mfbr;
+ u32 tx_max_funl;
struct brcms_fifo_info fifo_tb[NUM_FFPLD_FIFO];
-
};
/* used for flushing ampdu packets */
@@ -105,32 +151,75 @@ struct cb_del_ampdu_pars {
u16 tid;
};
-#define AMPDU_CLEANUPFLAG_RX (0x1)
-#define AMPDU_CLEANUPFLAG_TX (0x2)
+static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
+{
+ u32 rate, mcs;
-#define SCB_AMPDU_CUBBY(ampdu, scb) (&(scb->scb_ampdu))
-#define SCB_AMPDU_INI(scb_ampdu, tid) (&(scb_ampdu->ini[tid]))
+ for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
+ /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
+ /* 20MHz, No SGI */
+ rate = mcs_2_rate(mcs, false, false);
+ ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
+ /* 40 MHz, No SGI */
+ rate = mcs_2_rate(mcs, true, false);
+ ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
+ /* 20MHz, SGI */
+ rate = mcs_2_rate(mcs, false, true);
+ ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
+ /* 40 MHz, SGI */
+ rate = mcs_2_rate(mcs, true, true);
+ ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
+ }
+}
-static void brcms_c_ffpld_init(struct ampdu_info *ampdu);
-static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int f);
-static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f);
+static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
+{
+ if (BRCMS_PHY_11N_CAP(ampdu->wlc->band))
+ return true;
+ else
+ return false;
+}
-static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu,
- u8 dur);
-static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
- struct scb *scb);
-static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu);
+static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
+{
+ struct brcms_c_info *wlc = ampdu->wlc;
-#define brcms_c_ampdu_txflowcontrol(a, b, c) do {} while (0)
+ wlc->pub->_ampdu = false;
-static void
-brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu,
- struct scb *scb,
- struct sk_buff *p, struct tx_status *txs,
- u32 frmtxstatus, u32 frmtxstatus2);
+ if (on) {
+ if (!(wlc->pub->_n_enab & SUPPORT_11N)) {
+ wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
+ "nmode enabled\n", wlc->pub->unit);
+ return -ENOTSUPP;
+ }
+ if (!brcms_c_ampdu_cap(ampdu)) {
+ wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
+ "ampdu capable\n", wlc->pub->unit);
+ return -ENOTSUPP;
+ }
+ wlc->pub->_ampdu = on;
+ }
+
+ return 0;
+}
+
+static void brcms_c_ffpld_init(struct ampdu_info *ampdu)
+{
+ int i, j;
+ struct brcms_fifo_info *fifo;
+
+ for (j = 0; j < NUM_FFPLD_FIFO; j++) {
+ fifo = (ampdu->fifo_tb + j);
+ fifo->ampdu_pld_size = 0;
+ for (i = 0; i <= FFPLD_MAX_MCS; i++)
+ fifo->mcs2ampdu_table[i] = 255;
+ fifo->dmaxferrate = 0;
+ fifo->accum_txampdu = 0;
+ fifo->prev_txfunfl = 0;
+ fifo->accum_txfunfl = 0;
-static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu);
-static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on);
+ }
+}
struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
{
@@ -138,11 +227,9 @@ struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
int i;
ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC);
- if (!ampdu) {
- wiphy_err(wlc->wiphy, "wl%d: brcms_c_ampdu_attach: out of mem"
- "\n", wlc->pub->unit);
+ if (!ampdu)
return NULL;
- }
+
ampdu->wlc = wlc;
for (i = 0; i < AMPDU_MAX_SCB_TID; i++)
@@ -163,7 +250,10 @@ struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
- /* bump max ampdu rcv size to 64k for all 11n devices except 4321A0 and 4321A1 */
+ /*
+ * bump max ampdu rcv size to 64k for all 11n
+ * devices except 4321A0 and 4321A1
+ */
if (BRCMS_ISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2))
ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K;
else
@@ -189,27 +279,16 @@ struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
void brcms_c_ampdu_detach(struct ampdu_info *ampdu)
{
- int i;
-
- if (!ampdu)
- return;
-
- /* free all ini's which were to be freed on callbacks which were never called */
- for (i = 0; i < AMPDU_INI_FREE; i++) {
- kfree(ampdu->ini_free[i]);
- }
-
- brcms_c_module_unregister(ampdu->wlc->pub, "ampdu", ampdu);
kfree(ampdu);
}
static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
struct scb *scb)
{
- struct scb_ampdu *scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
+ struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
int i;
- scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu;
+ scb_ampdu->max_pdu = AMPDU_NUM_MPDU;
/* go back to legacy size if some preloading is occurring */
for (i = 0; i < NUM_FFPLD_FIFO; i++) {
@@ -221,7 +300,8 @@ static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
if (ampdu->max_pdu != AUTO)
scb_ampdu->max_pdu = (u8) ampdu->max_pdu;
- scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, AMPDU_SCB_MAX_RELEASE);
+ scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu,
+ AMPDU_SCB_MAX_RELEASE);
if (scb_ampdu->max_rx_ampdu_bytes)
scb_ampdu->release = min_t(u8, scb_ampdu->release,
@@ -234,24 +314,38 @@ static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu,
static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu)
{
- brcms_c_scb_ampdu_update_config(ampdu, ampdu->wlc->pub->global_scb);
+ brcms_c_scb_ampdu_update_config(ampdu, &ampdu->wlc->pri_scb);
}
-static void brcms_c_ffpld_init(struct ampdu_info *ampdu)
+static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
{
- int i, j;
- struct brcms_fifo_info *fifo;
+ int i;
+ u32 phy_rate, dma_rate, tmp;
+ u8 max_mpdu;
+ struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f);
- for (j = 0; j < NUM_FFPLD_FIFO; j++) {
- fifo = (ampdu->fifo_tb + j);
- fifo->ampdu_pld_size = 0;
- for (i = 0; i <= FFPLD_MAX_MCS; i++)
- fifo->mcs2ampdu_table[i] = 255;
- fifo->dmaxferrate = 0;
- fifo->accum_txampdu = 0;
- fifo->prev_txfunfl = 0;
- fifo->accum_txfunfl = 0;
+ /* recompute the dma rate */
+ /* note : we divide/multiply by 100 to avoid integer overflows */
+ max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
+ AMPDU_NUM_MPDU_LEGACY);
+ phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
+ dma_rate =
+ (((phy_rate / 100) *
+ (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
+ / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
+ fifo->dmaxferrate = dma_rate;
+ /* fill up the mcs2ampdu table; do not recalc the last mcs */
+ dma_rate = dma_rate >> 7;
+ for (i = 0; i < FFPLD_MAX_MCS; i++) {
+ /* shifting to keep it within integer range */
+ phy_rate = mcs_2_rate(i, true, false) >> 7;
+ if (phy_rate > dma_rate) {
+ tmp = ((fifo->ampdu_pld_size * phy_rate) /
+ ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
+ tmp = min_t(u32, tmp, 255);
+ fifo->mcs2ampdu_table[i] = (u8) tmp;
+ }
}
}
@@ -264,7 +358,7 @@ static void brcms_c_ffpld_init(struct ampdu_info *ampdu)
static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
{
struct ampdu_info *ampdu = wlc->ampdu;
- u32 phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
+ u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false);
u32 txunfl_ratio;
u8 max_mpdu;
u32 current_ampdu_cnt = 0;
@@ -275,7 +369,7 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
u16 cur_txunfl;
/* return if we got here for a different reason than underflows */
- cur_txunfl = brcms_c_read_shm(wlc,
+ cur_txunfl = brcms_b_read_shm(wlc->hw,
M_UCODE_MACSTAT +
offsetof(struct macstat, txfunfl[fid]));
new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
@@ -289,7 +383,7 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
return 1;
/* check if fifo is big enough */
- if (brcms_c_xmtfifo_sz_get(wlc, fid, &xmtfifo_sz))
+ if (brcms_b_xmtfifo_sz_get(wlc->hw, fid, &xmtfifo_sz))
return -1;
if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd)
@@ -317,13 +411,13 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl;
if (txunfl_ratio > ampdu->tx_max_funl) {
- if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) {
+ if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT)
fifo->accum_txfunfl = 0;
- }
+
return 0;
}
- max_mpdu =
- min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
+ max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS],
+ AMPDU_NUM_MPDU_LEGACY);
/* In case max value max_pdu is already lower than
the fifo depth, there is nothing more we can do.
@@ -345,11 +439,12 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
brcms_c_scb_ampdu_update_config_all(ampdu);
/*
- compute a new dma xfer rate for max_mpdu @ max mcs.
- This is the minimum dma rate that
- can achieve no underflow condition for the current mpdu size.
+ * compute a new dma xfer rate for max_mpdu @ max mcs.
+ * This is the minimum dma rate that can achieve no
+ * underflow condition for the current mpdu size.
+ *
+ * note : we divide/multiply by 100 to avoid integer overflows
*/
- /* note : we divide/multiply by 100 to avoid integer overflows */
fifo->dmaxferrate =
(((phy_rate / 100) *
(max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
@@ -379,38 +474,6 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
return 0;
}
-static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f)
-{
- int i;
- u32 phy_rate, dma_rate, tmp;
- u8 max_mpdu;
- struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f);
-
- /* recompute the dma rate */
- /* note : we divide/multiply by 100 to avoid integer overflows */
- max_mpdu =
- min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], AMPDU_NUM_MPDU_LEGACY);
- phy_rate = MCS_RATE(FFPLD_MAX_MCS, true, false);
- dma_rate =
- (((phy_rate / 100) *
- (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
- / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
- fifo->dmaxferrate = dma_rate;
-
- /* fill up the mcs2ampdu table; do not recalc the last mcs */
- dma_rate = dma_rate >> 7;
- for (i = 0; i < FFPLD_MAX_MCS; i++) {
- /* shifting to keep it within integer range */
- phy_rate = MCS_RATE(i, true, false) >> 7;
- if (phy_rate > dma_rate) {
- tmp = ((fifo->ampdu_pld_size * phy_rate) /
- ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1;
- tmp = min_t(u32, tmp, 255);
- fifo->mcs2ampdu_table[i] = (u8) tmp;
- }
- }
-}
-
void
brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
u8 ba_wsize, /* negotiated ba window size (in pdu) */
@@ -419,8 +482,8 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
struct scb_ampdu *scb_ampdu;
struct scb_ampdu_tid_ini *ini;
struct ampdu_info *ampdu = wlc->ampdu;
- struct scb *scb = wlc->pub->global_scb;
- scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
+ struct scb *scb = &wlc->pri_scb;
+ scb_ampdu = &scb->scb_ampdu;
if (!ampdu->ini_enable[tid]) {
wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
@@ -428,7 +491,7 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
return;
}
- ini = SCB_AMPDU_INI(scb_ampdu, tid);
+ ini = &scb_ampdu->ini[tid];
ini->tid = tid;
ini->scb = scb_ampdu->scb;
ini->ba_wsize = ba_wsize;
@@ -460,8 +523,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
struct scb_ampdu_tid_ini *ini;
u8 mcs = 0;
bool use_rts = false, use_cts = false;
- ratespec_t rspec = 0, rspec_fallback = 0;
- ratespec_t rts_rspec = 0, rts_rspec_fallback = 0;
+ u32 rspec = 0, rspec_fallback = 0;
+ u32 rts_rspec = 0, rts_rspec_fallback = 0;
u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
struct ieee80211_rts *rts;
u8 rr_retry_limit;
@@ -479,17 +542,16 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
f = ampdu->fifo_tb + prio2fifo[tid];
- scb = wlc->pub->global_scb;
- scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
+ scb = &wlc->pri_scb;
+ scb_ampdu = &scb->scb_ampdu;
ini = &scb_ampdu->ini[tid];
/* Let pressure continue to build ... */
qlen = pktq_plen(&qi->q, prec);
if (ini->tx_in_transit > 0 &&
- qlen < min(scb_ampdu->max_pdu, ini->ba_wsize)) {
+ qlen < min(scb_ampdu->max_pdu, ini->ba_wsize))
/* Collect multiple MPDU's to be sent in the next AMPDU */
return -EBUSY;
- }
/* at this point we intend to transmit an AMPDU */
rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
@@ -614,7 +676,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
}
is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
- sgi = PLCP3_ISSGI(plcp3) ? 1 : 0;
+ sgi = plcp3_issgi(plcp3) ? 1 : 0;
mcs = plcp0 & ~MIMO_PLCP_40MHZ;
max_ampdu_bytes =
min(scb_ampdu->max_rx_ampdu_bytes,
@@ -622,7 +684,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
if (is40)
mimo_ctlchbw =
- CHSPEC_SB_UPPER(BRCMS_BAND_PI_RADIO_CHANSPEC)
+ CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
+ wlc->band->pi))
? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
/* rebuild the rspec and rspec_fallback */
@@ -632,9 +695,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
if (fbr_iscck) /* CCK */
- rspec_fallback =
- CCK_RSPEC(CCK_PHY2MAC_RATE
- (txh->FragPLCPFallback[0]));
+ rspec_fallback = cck_rspec(cck_phy2mac_rate
+ (txh->FragPLCPFallback[0]));
else { /* MIMO */
rspec_fallback = RSPEC_MIMORATE;
rspec_fallback |=
@@ -657,7 +719,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
/* if (first mpdu for host agg) */
/* test whether to add more */
- if ((MCS_RATE(mcs, true, false) >= f->dmaxferrate) &&
+ if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) &&
(count == f->mcs2ampdu_table[mcs])) {
BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
" ampdu at %d for mcs %d\n",
@@ -665,13 +727,16 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
break;
}
- if (count == scb_ampdu->max_pdu) {
+ if (count == scb_ampdu->max_pdu)
break;
- }
- /* check to see if the next pkt is a candidate for aggregation */
+ /*
+ * check to see if the next pkt is
+ * a candidate for aggregation
+ */
p = pktq_ppeek(&qi->q, prec);
- tx_info = IEEE80211_SKB_CB(p); /* tx_info must be checked with current p */
+ /* tx_info must be checked with current p */
+ tx_info = IEEE80211_SKB_CB(p);
if (p) {
if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
@@ -686,8 +751,11 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
continue;
}
- /* check if there are enough descriptors available */
- if (TXAVAIL(wlc, fifo) <= (seg_cnt + 1)) {
+ /*
+ * check if there are enough
+ * descriptors available
+ */
+ if (*wlc->core->txavail[fifo] <= seg_cnt + 1) {
wiphy_err(wiphy, "%s: No fifo space "
"!!\n", __func__);
p = NULL;
@@ -745,7 +813,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
}
/* set the preload length */
- if (MCS_RATE(mcs, true, false) >= f->dmaxferrate) {
+ if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
dma_len = min(dma_len, f->ampdu_pld_size);
txh->PreloadSize = cpu_to_le16(dma_len);
} else
@@ -797,10 +865,10 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
/* inform rate_sel if it this is a rate probe pkt */
frameid = le16_to_cpu(txh->TxFrameID);
- if (frameid & TXFID_RATE_PROBE_MASK) {
+ if (frameid & TXFID_RATE_PROBE_MASK)
wiphy_err(wiphy, "%s: XXX what to do with "
"TXFID_RATE_PROBE_MASK!?\n", __func__);
- }
+
for (i = 0; i < count; i++)
brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1),
ampdu->txpkt_weight);
@@ -810,62 +878,6 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
return err;
}
-void
-brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
- struct sk_buff *p, struct tx_status *txs)
-{
- struct scb_ampdu *scb_ampdu;
- struct brcms_c_info *wlc = ampdu->wlc;
- struct scb_ampdu_tid_ini *ini;
- u32 s1 = 0, s2 = 0;
- struct ieee80211_tx_info *tx_info;
-
- tx_info = IEEE80211_SKB_CB(p);
-
- /* BMAC_NOTE: For the split driver, second level txstatus comes later
- * So if the ACK was received then wait for the second level else just
- * call the first one
- */
- if (txs->status & TX_STATUS_ACK_RCV) {
- u8 status_delay = 0;
-
- /* wait till the next 8 bytes of txstatus is available */
- while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
- udelay(1);
- status_delay++;
- if (status_delay > 10) {
- return; /* error condition */
- }
- }
-
- s2 = R_REG(&wlc->regs->frmtxstatus2);
- }
-
- if (likely(scb)) {
- scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
- ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
- brcms_c_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
- } else {
- /* loop through all pkts and free */
- u8 queue = txs->frameid & TXFID_QUEUE_MASK;
- struct d11txh *txh;
- u16 mcl;
- while (p) {
- tx_info = IEEE80211_SKB_CB(p);
- txh = (struct d11txh *) p->data;
- mcl = le16_to_cpu(txh->MacTxControlLow);
- brcmu_pkt_buf_free_skb(p);
- /* break out if last packet of ampdu */
- if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
- TXC_AMPDU_LAST)
- break;
- p = GETNEXTTXP(wlc, queue);
- }
- brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
- }
- brcms_c_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
-}
-
static void
brcms_c_ampdu_rate_status(struct brcms_c_info *wlc,
struct ieee80211_tx_info *tx_info,
@@ -881,8 +893,6 @@ brcms_c_ampdu_rate_status(struct brcms_c_info *wlc,
}
}
-#define SHORTNAME "AMPDU status"
-
static void
brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
struct sk_buff *p, struct tx_status *txs,
@@ -912,10 +922,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
memset(hole, 0, sizeof(hole));
#endif
- scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
+ scb_ampdu = &scb->scb_ampdu;
tid = (u8) (p->priority);
- ini = SCB_AMPDU_INI(scb_ampdu, tid);
+ ini = &scb_ampdu->ini[tid];
retry_limit = ampdu->retry_limit_tid[tid];
rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
memset(bitmap, 0, sizeof(bitmap));
@@ -923,9 +933,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
supr_status = txs->status & TX_STATUS_SUPR_MASK;
if (txs->status & TX_STATUS_ACK_RCV) {
- if (TX_STATUS_SUPR_UF == supr_status) {
+ if (TX_STATUS_SUPR_UF == supr_status)
update_rate = false;
- }
WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE));
start_seq = txs->sequence >> SEQNUM_SHIFT;
@@ -967,15 +976,17 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
supr_status == TX_STATUS_SUPR_EXPTIME) {
retry = false;
} else if (supr_status == TX_STATUS_SUPR_EXPTIME) {
- /* TX underflow : try tuning pre-loading or ampdu size */
+ /* TX underflow:
+ * try tuning pre-loading or ampdu size
+ */
} else if (supr_status == TX_STATUS_SUPR_FRAG) {
- /* if there were underflows, but pre-loading is not active,
- notify rate adaptation.
+ /*
+ * if there were underflows, but pre-loading
+ * is not active, notify rate adaptation.
*/
if (brcms_c_ffpld_check_txfunfl(wlc,
- prio2fifo[tid]) > 0) {
+ prio2fifo[tid]) > 0)
tx_error = true;
- }
}
} else if (txs->phyerr) {
update_rate = false;
@@ -983,7 +994,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
"error (0x%x)\n", wlc->pub->unit,
txs->phyerr);
- if (WL_ERROR_ON()) {
+ if (brcm_msg_level & LOG_ERROR_VAL) {
brcmu_prpkt("txpkt (AMPDU)", p);
brcms_c_print_txdesc((struct d11txh *) p->data);
}
@@ -1019,7 +1030,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
ini->tx_in_transit--;
ini->txretry[index] = 0;
- /* ampdu_ack_len: number of acked aggregated frames */
+ /*
+ * ampdu_ack_len:
+ * number of acked aggregated frames
+ */
/* ampdu_len: number of aggregated frames */
brcms_c_ampdu_rate_status(wlc, tx_info, txs,
mcs);
@@ -1044,11 +1058,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
if (retry && (txrate[0].count < (int)retry_limit)) {
ini->txretry[index]++;
ini->tx_in_transit--;
- /* Use high prededence for retransmit to give some punch */
+ /*
+ * Use high prededence for retransmit to
+ * give some punch
+ */
/* brcms_c_txq_enq(wlc, scb, p,
* BRCMS_PRIO_TO_PREC(tid)); */
brcms_c_txq_enq(wlc, scb, p,
- BRCMS_PRIO_TO_HI_PREC(tid));
+ BRCMS_PRIO_TO_HI_PREC(tid));
} else {
/* Retry timeout */
ini->tx_in_transit--;
@@ -1060,7 +1077,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
skb_pull(p, D11_PHY_HDR_LEN);
skb_pull(p, D11_TXH_LEN);
wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_"
- "transit %d\n", SHORTNAME, seq,
+ "transit %d\n", "AMPDU status", seq,
ini->tx_in_transit);
ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
p);
@@ -1073,7 +1090,7 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
TXC_AMPDU_LAST)
break;
- p = GETNEXTTXP(wlc, queue);
+ p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
}
brcms_c_send_q(wlc);
@@ -1083,55 +1100,58 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
}
-static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
+void
+brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
+ struct sk_buff *p, struct tx_status *txs)
{
+ struct scb_ampdu *scb_ampdu;
struct brcms_c_info *wlc = ampdu->wlc;
+ struct scb_ampdu_tid_ini *ini;
+ u32 s1 = 0, s2 = 0;
+ struct ieee80211_tx_info *tx_info;
- wlc->pub->_ampdu = false;
-
- if (on) {
- if (!N_ENAB(wlc->pub)) {
- wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
- "nmode enabled\n", wlc->pub->unit);
- return -ENOTSUPP;
- }
- if (!brcms_c_ampdu_cap(ampdu)) {
- wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
- "ampdu capable\n", wlc->pub->unit);
- return -ENOTSUPP;
- }
- wlc->pub->_ampdu = on;
- }
+ tx_info = IEEE80211_SKB_CB(p);
- return 0;
-}
+ /* BMAC_NOTE: For the split driver, second level txstatus comes later
+ * So if the ACK was received then wait for the second level else just
+ * call the first one
+ */
+ if (txs->status & TX_STATUS_ACK_RCV) {
+ u8 status_delay = 0;
-static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
-{
- if (BRCMS_PHY_11N_CAP(ampdu->wlc->band))
- return true;
- else
- return false;
-}
+ /* wait till the next 8 bytes of txstatus is available */
+ while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) {
+ udelay(1);
+ status_delay++;
+ if (status_delay > 10)
+ return; /* error condition */
+ }
-static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur)
-{
- u32 rate, mcs;
+ s2 = R_REG(&wlc->regs->frmtxstatus2);
+ }
- for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) {
- /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */
- /* 20MHz, No SGI */
- rate = MCS_RATE(mcs, false, false);
- ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3;
- /* 40 MHz, No SGI */
- rate = MCS_RATE(mcs, true, false);
- ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3;
- /* 20MHz, SGI */
- rate = MCS_RATE(mcs, false, true);
- ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3;
- /* 40 MHz, SGI */
- rate = MCS_RATE(mcs, true, true);
- ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3;
+ if (scb) {
+ scb_ampdu = &scb->scb_ampdu;
+ ini = &scb_ampdu->ini[p->priority];
+ brcms_c_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
+ } else {
+ /* loop through all pkts and free */
+ u8 queue = txs->frameid & TXFID_QUEUE_MASK;
+ struct d11txh *txh;
+ u16 mcl;
+ while (p) {
+ tx_info = IEEE80211_SKB_CB(p);
+ txh = (struct d11txh *) p->data;
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+ brcmu_pkt_buf_free_skb(p);
+ /* break out if last packet of ampdu */
+ if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
+ TXC_AMPDU_LAST)
+ break;
+ p = dma_getnexttxp(wlc->hw->di[queue],
+ DMA_RANGE_TRANSMITTED);
+ }
+ brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
}
}
@@ -1142,7 +1162,7 @@ void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc)
/* driver needs to write the ta in the template; ta is at offset 16 */
memset(template, 0, sizeof(template));
memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN);
- brcms_c_write_template_ram(wlc, (T_BA_TPL_BASE + 16),
+ brcms_b_write_template_ram(wlc->hw, (T_BA_TPL_BASE + 16),
(T_RAM_ACCESS_SZ * 2),
template);
}
@@ -1156,14 +1176,17 @@ void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu)
{
struct brcms_c_info *wlc = ampdu->wlc;
- /* Extend ucode internal watchdog timer to match larger received frames */
+ /*
+ * Extend ucode internal watchdog timer to
+ * match larger received frames
+ */
if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) ==
IEEE80211_HT_MAX_AMPDU_64K) {
- brcms_c_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
- brcms_c_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
+ brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX);
+ brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX);
} else {
- brcms_c_write_shm(wlc, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
- brcms_c_write_shm(wlc, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
+ brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF);
+ brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF);
}
}
@@ -1211,9 +1234,8 @@ void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
ampdu_pars.sta = sta;
ampdu_pars.tid = tid;
- for (prec = 0; prec < pq->num_prec; prec++) {
+ for (prec = 0; prec < pq->num_prec; prec++)
brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
(void *)&ampdu_pars);
- }
brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
}
diff --git a/drivers/staging/brcm80211/brcmsmac/antsel.c b/drivers/staging/brcm80211/brcmsmac/antsel.c
index c4e76c093ae9..a47ce25cb9a2 100644
--- a/drivers/staging/brcm80211/brcmsmac/antsel.c
+++ b/drivers/staging/brcm80211/brcmsmac/antsel.c
@@ -18,7 +18,6 @@
#include <net/mac80211.h>
#include "types.h"
-#include "bmac.h"
#include "main.h"
#include "phy_shim.h"
#include "antsel.h"
@@ -50,55 +49,76 @@
#define ANT_SELCFG_NUM_2x4 4
#define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */
-/* static functions */
-static int brcms_c_antsel_cfgupd(struct antsel_info *asi,
- struct brcms_antselcfg *antsel);
-static u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id);
-static u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg);
-static void brcms_c_antsel_init_cfg(struct antsel_info *asi,
- struct brcms_antselcfg *antsel,
- bool auto_sel);
-
-const u16 mimo_2x4_div_antselpat_tbl[] = {
+static const u16 mimo_2x4_div_antselpat_tbl[] = {
0, 0, 0x9, 0xa, /* ant0: 0 ant1: 2,3 */
0, 0, 0x5, 0x6, /* ant0: 1 ant1: 2,3 */
0, 0, 0, 0, /* n.a. */
0, 0, 0, 0 /* n.a. */
};
-const u8 mimo_2x4_div_antselid_tbl[16] = {
+static const u8 mimo_2x4_div_antselid_tbl[16] = {
0, 0, 0, 0, 0, 2, 3, 0,
0, 0, 1, 0, 0, 0, 0, 0 /* pat to antselid */
};
-const u16 mimo_2x3_div_antselpat_tbl[] = {
+static const u16 mimo_2x3_div_antselpat_tbl[] = {
16, 0, 1, 16, /* ant0: 0 ant1: 1,2 */
16, 16, 16, 16, /* n.a. */
16, 2, 16, 16, /* ant0: 2 ant1: 1 */
16, 16, 16, 16 /* n.a. */
};
-const u8 mimo_2x3_div_antselid_tbl[16] = {
+static const u8 mimo_2x3_div_antselid_tbl[16] = {
0, 1, 2, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */
};
+/* boardlevel antenna selection: init antenna selection structure */
+static void
+brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel,
+ bool auto_sel)
+{
+ if (asi->antsel_type == ANTSEL_2x3) {
+ u8 antcfg_def = ANT_SELCFG_DEF_2x3 |
+ ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0);
+ antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def;
+ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def;
+ antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def;
+ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def;
+ antsel->num_antcfg = ANT_SELCFG_NUM_2x3;
+
+ } else if (asi->antsel_type == ANTSEL_2x4) {
+
+ antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4;
+ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4;
+ antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4;
+ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4;
+ antsel->num_antcfg = ANT_SELCFG_NUM_2x4;
+
+ } else { /* no antenna selection available */
+
+ antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2;
+ antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2;
+ antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2;
+ antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2;
+ antsel->num_antcfg = 0;
+ }
+}
+
struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
{
struct antsel_info *asi;
+ struct si_pub *sih = wlc->hw->sih;
asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
- if (!asi) {
- wiphy_err(wlc->wiphy, "wl%d: brcms_c_antsel_attach: out of "
- "mem\n", wlc->pub->unit);
+ if (!asi)
return NULL;
- }
asi->wlc = wlc;
asi->pub = wlc->pub;
asi->antsel_type = ANTSEL_NA;
asi->antsel_avail = false;
- asi->antsel_antswitch = (u8) getintvar(asi->pub->vars, "antswitch");
+ asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH);
if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) {
switch (asi->antsel_antswitch) {
@@ -108,27 +128,26 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
/* 4321/2 board with 2x3 switch logic */
asi->antsel_type = ANTSEL_2x3;
/* Antenna selection availability */
- if (((u16) getintvar(asi->pub->vars, "aa2g") == 7) ||
- ((u16) getintvar(asi->pub->vars, "aa5g") == 7)) {
+ if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) ||
+ ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) {
asi->antsel_avail = true;
- } else
- if (((u16) getintvar(asi->pub->vars, "aa2g") ==
- 3)
- || ((u16) getintvar(asi->pub->vars, "aa5g")
- == 3)) {
+ } else if (
+ (u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 ||
+ (u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) {
asi->antsel_avail = false;
} else {
asi->antsel_avail = false;
wiphy_err(wlc->wiphy, "antsel_attach: 2o3 "
"board cfg invalid\n");
}
+
break;
default:
break;
}
} else if ((asi->pub->sromrev == 4) &&
- ((u16) getintvar(asi->pub->vars, "aa2g") == 7) &&
- ((u16) getintvar(asi->pub->vars, "aa5g") == 0)) {
+ ((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) &&
+ ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) {
/* hack to match old 4321CB2 cards with 2of3 antenna switch */
asi->antsel_type = ANTSEL_2x3;
asi->antsel_avail = true;
@@ -152,6 +171,64 @@ void brcms_c_antsel_detach(struct antsel_info *asi)
kfree(asi);
}
+/*
+ * boardlevel antenna selection:
+ * convert ant_cfg to mimo_antsel (ucode interface)
+ */
+static u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg)
+{
+ u8 idx = BRCMS_ANTIDX_11N(BRCMS_ANTSEL_11N(ant_cfg));
+ u16 mimo_antsel = 0;
+
+ if (asi->antsel_type == ANTSEL_2x4) {
+ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
+ mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf);
+ return mimo_antsel;
+
+ } else if (asi->antsel_type == ANTSEL_2x3) {
+ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
+ mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf);
+ return mimo_antsel;
+ }
+
+ return mimo_antsel;
+}
+
+/* boardlevel antenna selection: ucode interface control */
+static int brcms_c_antsel_cfgupd(struct antsel_info *asi,
+ struct brcms_antselcfg *antsel)
+{
+ struct brcms_c_info *wlc = asi->wlc;
+ u8 ant_cfg;
+ u16 mimo_antsel;
+
+ /* 1) Update TX antconfig for all frames that are not unicast data
+ * (aka default TX)
+ */
+ ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF];
+ mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg);
+ brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_TXDFLT, mimo_antsel);
+ /*
+ * Update driver stats for currently selected
+ * default tx/rx antenna config
+ */
+ asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg;
+
+ /* 2) Update RX antconfig for all frames that are not unicast data
+ * (aka default RX)
+ */
+ ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF];
+ mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg);
+ brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_RXDFLT, mimo_antsel);
+ /*
+ * Update driver stats for currently selected
+ * default tx/rx antenna config
+ */
+ asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg;
+
+ return 0;
+}
+
void brcms_c_antsel_init(struct antsel_info *asi)
{
if ((asi->antsel_type == ANTSEL_2x3) ||
@@ -159,36 +236,23 @@ void brcms_c_antsel_init(struct antsel_info *asi)
brcms_c_antsel_cfgupd(asi, &asi->antcfg_11n);
}
-/* boardlevel antenna selection: init antenna selection structure */
-static void
-brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel,
- bool auto_sel)
+/* boardlevel antenna selection: convert id to ant_cfg */
+static u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id)
{
- if (asi->antsel_type == ANTSEL_2x3) {
- u8 antcfg_def = ANT_SELCFG_DEF_2x3 |
- ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0);
- antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def;
- antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def;
- antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def;
- antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def;
- antsel->num_antcfg = ANT_SELCFG_NUM_2x3;
-
- } else if (asi->antsel_type == ANTSEL_2x4) {
-
- antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4;
- antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4;
- antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4;
- antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4;
- antsel->num_antcfg = ANT_SELCFG_NUM_2x4;
+ u8 antcfg = ANT_SELCFG_DEF_2x2;
- } else { /* no antenna selection available */
+ if (asi->antsel_type == ANTSEL_2x4) {
+ /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
+ antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2));
+ return antcfg;
- antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2;
- antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2;
- antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2;
- antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2;
- antsel->num_antcfg = 0;
+ } else if (asi->antsel_type == ANTSEL_2x3) {
+ /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
+ antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1));
+ return antcfg;
}
+
+ return antcfg;
}
void
@@ -241,71 +305,3 @@ u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel)
return antselid;
}
-
-/* boardlevel antenna selection: convert id to ant_cfg */
-static u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id)
-{
- u8 antcfg = ANT_SELCFG_DEF_2x2;
-
- if (asi->antsel_type == ANTSEL_2x4) {
- /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
- antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2));
- return antcfg;
-
- } else if (asi->antsel_type == ANTSEL_2x3) {
- /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
- antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1));
- return antcfg;
- }
-
- return antcfg;
-}
-
-/* boardlevel antenna selection: convert ant_cfg to mimo_antsel (ucode interface) */
-static u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg)
-{
- u8 idx = BRCMS_ANTIDX_11N(BRCMS_ANTSEL_11N(ant_cfg));
- u16 mimo_antsel = 0;
-
- if (asi->antsel_type == ANTSEL_2x4) {
- /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */
- mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf);
- return mimo_antsel;
-
- } else if (asi->antsel_type == ANTSEL_2x3) {
- /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */
- mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf);
- return mimo_antsel;
- }
-
- return mimo_antsel;
-}
-
-/* boardlevel antenna selection: ucode interface control */
-static int brcms_c_antsel_cfgupd(struct antsel_info *asi,
- struct brcms_antselcfg *antsel)
-{
- struct brcms_c_info *wlc = asi->wlc;
- u8 ant_cfg;
- u16 mimo_antsel;
-
- /* 1) Update TX antconfig for all frames that are not unicast data
- * (aka default TX)
- */
- ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF];
- mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg);
- brcms_c_write_shm(wlc, M_MIMO_ANTSEL_TXDFLT, mimo_antsel);
- /* Update driver stats for currently selected default tx/rx antenna config */
- asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg;
-
- /* 2) Update RX antconfig for all frames that are not unicast data
- * (aka default RX)
- */
- ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF];
- mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg);
- brcms_c_write_shm(wlc, M_MIMO_ANTSEL_RXDFLT, mimo_antsel);
- /* Update driver stats for currently selected default tx/rx antenna config */
- asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg;
-
- return 0;
-}
diff --git a/drivers/staging/brcm80211/brcmsmac/bmac.c b/drivers/staging/brcm80211/brcmsmac/bmac.c
deleted file mode 100644
index b25c51705566..000000000000
--- a/drivers/staging/brcm80211/brcmsmac/bmac.c
+++ /dev/null
@@ -1,3593 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <linux/pci.h>
-#include <net/mac80211.h>
-
-#include <brcm_hw_ids.h>
-#include <aiutils.h>
-#include <chipcommon.h>
-#include "types.h"
-#include "rate.h"
-#include "phy/phy_hal.h"
-#include "channel.h"
-#include "main.h"
-#include "ucode_loader.h"
-#include "mac80211_if.h"
-#include "bmac.h"
-
-#define TIMER_INTERVAL_WATCHDOG_BMAC 1000 /* watchdog timer, in unit of ms */
-
-#define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */
-#define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us, default */
-#define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us, default */
-#define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */
-
-#define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */
-
-#ifndef BMAC_DUP_TO_REMOVE
-
-#define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */
-
-#endif /* BMAC_DUP_TO_REMOVE */
-
-#define DMAREG(wlc_hw, direction, fifonum) \
- ((direction == DMA_TX) ? \
- (void *)&(wlc_hw->regs->fifo64regs[fifonum].dmaxmt) : \
- (void *)&(wlc_hw->regs->fifo64regs[fifonum].dmarcv))
-
-#define APHY_SLOT_TIME 9
-#define BPHY_SLOT_TIME 20
-
-/*
- * The following table lists the buffer memory allocated to xmt fifos in HW.
- * the size is in units of 256bytes(one block), total size is HW dependent
- * ucode has default fifo partition, sw can overwrite if necessary
- *
- * This is documented in twiki under the topic UcodeTxFifo. Please ensure
- * the twiki is updated before making changes.
- */
-
-#define XMTFIFOTBL_STARTREV 20 /* Starting corerev for the fifo size table */
-
-static u16 xmtfifo_sz[][NFIFO] = {
- {20, 192, 192, 21, 17, 5}, /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
- {9, 58, 22, 14, 14, 5}, /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
- {20, 192, 192, 21, 17, 5}, /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
- {20, 192, 192, 21, 17, 5}, /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
- {9, 58, 22, 14, 14, 5}, /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
-};
-
-static void brcms_b_clkctl_clk(struct brcms_hardware *wlc, uint mode);
-static void brcms_b_coreinit(struct brcms_c_info *wlc);
-
-/* used by wlc_wakeucode_init() */
-static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
- const struct d11init *inits);
-static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[],
- const uint nbytes);
-static void brcms_ucode_download(struct brcms_hardware *wlc);
-static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw);
-
-/* used by brcms_c_dpc() */
-static bool brcms_b_dotxstatus(struct brcms_hardware *wlc,
- struct tx_status *txs, u32 s2);
-static bool brcms_b_txstatus(struct brcms_hardware *wlc, bool bound,
- bool *fatal);
-static bool brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound);
-
-/* used by brcms_c_down() */
-static void brcms_c_flushqueues(struct brcms_c_info *wlc);
-
-static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs);
-static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw);
-static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw);
-static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
- uint tx_fifo);
-static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
- uint tx_fifo);
-static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
- uint tx_fifo);
-
-/* Low Level Prototypes */
-static int brcms_b_bandtype(struct brcms_hardware *wlc_hw);
-static void brcms_b_info_init(struct brcms_hardware *wlc_hw);
-static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want);
-static u16 brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset,
- u32 sel);
-static void brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset,
- u16 v, u32 sel);
-static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk);
-static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme);
-static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw);
-static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw);
-static bool brcms_c_validboardtype(struct brcms_hardware *wlc);
-static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw);
-static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw);
-static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw);
-static void brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init);
-static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw);
-static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool want,
- mbool flags);
-static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw);
-static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw);
-static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc);
-static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask);
-static void brcms_c_gpio_init(struct brcms_c_info *wlc);
-static void brcms_c_write_hw_bcntemplate0(struct brcms_hardware *wlc_hw,
- void *bcn, int len);
-static void brcms_c_write_hw_bcntemplate1(struct brcms_hardware *wlc_hw,
- void *bcn, int len);
-static void brcms_b_bsinit(struct brcms_c_info *wlc, chanspec_t chanspec);
-static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit);
-static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
- chanspec_t chanspec);
-static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
- bool shortslot);
-static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw);
-static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
- u8 rate);
-
-/* === Low Level functions === */
-
-void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
-{
- wlc_hw->shortslot = shortslot;
-
- if (BAND_2G(brcms_b_bandtype(wlc_hw)) && wlc_hw->up) {
- brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
- brcms_b_update_slot_timing(wlc_hw, shortslot);
- brcms_c_enable_mac(wlc_hw->wlc);
- }
-}
-
-/*
- * Update the slot timing for standard 11b/g (20us slots)
- * or shortslot 11g (9us slots)
- * The PSM needs to be suspended for this call.
- */
-static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
- bool shortslot)
-{
- d11regs_t *regs;
-
- regs = wlc_hw->regs;
-
- if (shortslot) {
- /* 11g short slot: 11a timing */
- W_REG(&regs->ifs_slot, 0x0207); /* APHY_SLOT_TIME */
- brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);
- } else {
- /* 11g long slot: 11b timing */
- W_REG(&regs->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */
- brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);
- }
-}
-
-static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
-{
- struct wiphy *wiphy = wlc_hw->wlc->wiphy;
-
- /* init microcode host flags */
- brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
-
- /* do band-specific ucode IHR, SHM, and SCR inits */
- if (D11REV_IS(wlc_hw->corerev, 23)) {
- if (BRCMS_ISNPHY(wlc_hw->band)) {
- brcms_c_write_inits(wlc_hw, d11n0bsinitvals16);
- } else {
- wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
- " %d\n", __func__, wlc_hw->unit,
- wlc_hw->corerev);
- }
- } else {
- if (D11REV_IS(wlc_hw->corerev, 24)) {
- if (BRCMS_ISLCNPHY(wlc_hw->band)) {
- brcms_c_write_inits(wlc_hw,
- d11lcn0bsinitvals24);
- } else
- wiphy_err(wiphy, "%s: wl%d: unsupported phy in"
- " core rev %d\n", __func__,
- wlc_hw->unit, wlc_hw->corerev);
- } else {
- wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev);
- }
- }
-}
-
-/* switch to new band but leave it inactive */
-static u32 brcms_c_setband_inact(struct brcms_c_info *wlc,
- uint bandunit)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- u32 macintmask;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
-
- /* disable interrupts */
- macintmask = brcms_intrsoff(wlc->wl);
-
- /* radio off */
- wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
-
- brcms_b_core_phy_clk(wlc_hw, OFF);
-
- brcms_c_setxband(wlc_hw, bandunit);
-
- return macintmask;
-}
-
-/* Process received frames */
-/*
- * Return true if more frames need to be processed. false otherwise.
- * Param 'bound' indicates max. # frames to process before break out.
- */
-static bool
-brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
-{
- struct sk_buff *p;
- struct sk_buff *head = NULL;
- struct sk_buff *tail = NULL;
- uint n = 0;
- uint bound_limit = bound ? wlc_hw->wlc->pub->tunables->rxbnd : -1;
- struct brcms_d11rxhdr *wlc_rxhdr = NULL;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
- /* gather received frames */
- while ((p = dma_rx(wlc_hw->di[fifo]))) {
-
- if (!tail)
- head = tail = p;
- else {
- tail->prev = p;
- tail = p;
- }
-
- /* !give others some time to run! */
- if (++n >= bound_limit)
- break;
- }
-
- /* post more rbufs */
- dma_rxfill(wlc_hw->di[fifo]);
-
- /* process each frame */
- while ((p = head) != NULL) {
- head = head->prev;
- p->prev = NULL;
-
- wlc_rxhdr = (struct brcms_d11rxhdr *) p->data;
-
- /* compute the RSSI from d11rxhdr and record it in wlc_rxd11hr */
- wlc_phy_rssi_compute(wlc_hw->band->pi, wlc_rxhdr);
-
- brcms_c_recv(wlc_hw->wlc, p);
- }
-
- return n >= bound_limit;
-}
-
-/* second-level interrupt processing
- * Return true if another dpc needs to be re-scheduled. false otherwise.
- * Param 'bounded' indicates if applicable loops should be bounded.
- */
-bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
-{
- u32 macintstatus;
- struct brcms_hardware *wlc_hw = wlc->hw;
- d11regs_t *regs = wlc_hw->regs;
- bool fatal = false;
- struct wiphy *wiphy = wlc->wiphy;
-
- if (DEVICEREMOVED(wlc)) {
- wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
- __func__);
- brcms_down(wlc->wl);
- return false;
- }
-
- /* grab and clear the saved software intstatus bits */
- macintstatus = wlc->macintstatus;
- wlc->macintstatus = 0;
-
- BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
- wlc_hw->unit, macintstatus);
-
- WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
-
- /* BCN template is available */
- /* ZZZ: Use AP_ACTIVE ? */
- if (AP_ENAB(wlc->pub) && (!APSTA_ENAB(wlc->pub))
- && (macintstatus & MI_BCNTPL)) {
- brcms_c_update_beacon(wlc);
- }
-
- /* tx status */
- if (macintstatus & MI_TFS) {
- if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
- wlc->macintstatus |= MI_TFS;
- if (fatal) {
- wiphy_err(wiphy, "MI_TFS: fatal\n");
- goto fatal;
- }
- }
-
- if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
- brcms_c_tbtt(wlc);
-
- /* ATIM window end */
- if (macintstatus & MI_ATIMWINEND) {
- BCMMSG(wlc->wiphy, "end of ATIM window\n");
- OR_REG(&regs->maccommand, wlc->qvalid);
- wlc->qvalid = 0;
- }
-
- /* received data or control frame, MI_DMAINT is indication of RX_FIFO interrupt */
- if (macintstatus & MI_DMAINT)
- if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
- wlc->macintstatus |= MI_DMAINT;
-
- /* TX FIFO suspend/flush completion */
- if (macintstatus & MI_TXSTOP)
- brcms_b_tx_fifo_suspended(wlc_hw, TX_DATA_FIFO);
-
- /* noise sample collected */
- if (macintstatus & MI_BG_NOISE) {
- wlc_phy_noise_sample_intr(wlc_hw->band->pi);
- }
-
- if (macintstatus & MI_GP0) {
- wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
- "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
-
- printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
- __func__, wlc_hw->sih->chip,
- wlc_hw->sih->chiprev);
- /* big hammer */
- brcms_init(wlc->wl);
- }
-
- /* gptimer timeout */
- if (macintstatus & MI_TO) {
- W_REG(&regs->gptimer, 0);
- }
-
- if (macintstatus & MI_RFDISABLE) {
- BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
- " RF Disable Input\n", wlc_hw->unit);
- brcms_rfkill_set_hw_state(wlc->wl);
- }
-
- /* send any enq'd tx packets. Just makes sure to jump start tx */
- if (!pktq_empty(&wlc->pkt_queue->q))
- brcms_c_send_q(wlc);
-
- /* it isn't done and needs to be resched if macintstatus is non-zero */
- return wlc->macintstatus != 0;
-
- fatal:
- brcms_init(wlc->wl);
- return wlc->macintstatus != 0;
-}
-
-/* common low-level watchdog code */
-void brcms_b_watchdog(void *arg)
-{
- struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
- struct brcms_hardware *wlc_hw = wlc->hw;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- if (!wlc_hw->up)
- return;
-
- /* increment second count */
- wlc_hw->now++;
-
- /* Check for FIFO error interrupts */
- brcms_b_fifoerrors(wlc_hw);
-
- /* make sure RX dma has buffers */
- dma_rxfill(wlc->hw->di[RX_FIFO]);
-
- wlc_phy_watchdog(wlc_hw->band->pi);
-}
-
-void
-brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
- bool mute, struct txpwr_limits *txpwr)
-{
- uint bandunit;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
-
- wlc_hw->chanspec = chanspec;
-
- /* Switch bands if necessary */
- if (NBANDS_HW(wlc_hw) > 1) {
- bandunit = CHSPEC_BANDUNIT(chanspec);
- if (wlc_hw->band->bandunit != bandunit) {
- /* brcms_b_setband disables other bandunit,
- * use light band switch if not up yet
- */
- if (wlc_hw->up) {
- wlc_phy_chanspec_radio_set(wlc_hw->
- bandstate[bandunit]->
- pi, chanspec);
- brcms_b_setband(wlc_hw, bandunit, chanspec);
- } else {
- brcms_c_setxband(wlc_hw, bandunit);
- }
- }
- }
-
- wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
-
- if (!wlc_hw->up) {
- if (wlc_hw->clk)
- wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
- chanspec);
- wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
- } else {
- wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
- wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
-
- /* Update muting of the channel */
- brcms_b_mute(wlc_hw, mute, 0);
- }
-}
-
-int brcms_b_state_get(struct brcms_hardware *wlc_hw,
- struct brcms_b_state *state)
-{
- state->machwcap = wlc_hw->machwcap;
-
- return 0;
-}
-
-static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
-{
- uint i;
- char name[8];
- /* ucode host flag 2 needed for pio mode, independent of band and fifo */
- u16 pio_mhf2 = 0;
- struct brcms_hardware *wlc_hw = wlc->hw;
- uint unit = wlc_hw->unit;
- struct brcms_tunables *tune = wlc->pub->tunables;
- struct wiphy *wiphy = wlc->wiphy;
-
- /* name and offsets for dma_attach */
- snprintf(name, sizeof(name), "wl%d", unit);
-
- if (wlc_hw->di[0] == 0) { /* Init FIFOs */
- uint addrwidth;
- int dma_attach_err = 0;
- /* Find out the DMA addressing capability and let OS know
- * All the channels within one DMA core have 'common-minimum' same
- * capability
- */
- addrwidth =
- dma_addrwidth(wlc_hw->sih, DMAREG(wlc_hw, DMA_TX, 0));
-
- if (!wl_alloc_dma_resources(wlc_hw->wlc->wl, addrwidth)) {
- wiphy_err(wiphy, "wl%d: wlc_attach: alloc_dma_"
- "resources failed\n", unit);
- return false;
- }
-
- /*
- * FIFO 0
- * TX: TX_AC_BK_FIFO (TX AC Background data packets)
- * RX: RX_FIFO (RX data packets)
- */
- wlc_hw->di[0] = dma_attach(name, wlc_hw->sih,
- (wme ? DMAREG(wlc_hw, DMA_TX, 0) :
- NULL), DMAREG(wlc_hw, DMA_RX, 0),
- (wme ? tune->ntxd : 0), tune->nrxd,
- tune->rxbufsz, -1, tune->nrxbufpost,
- BRCMS_HWRXOFF, &brcm_msg_level);
- dma_attach_err |= (NULL == wlc_hw->di[0]);
-
- /*
- * FIFO 1
- * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
- * (legacy) TX_DATA_FIFO (TX data packets)
- * RX: UNUSED
- */
- wlc_hw->di[1] = dma_attach(name, wlc_hw->sih,
- DMAREG(wlc_hw, DMA_TX, 1), NULL,
- tune->ntxd, 0, 0, -1, 0, 0,
- &brcm_msg_level);
- dma_attach_err |= (NULL == wlc_hw->di[1]);
-
- /*
- * FIFO 2
- * TX: TX_AC_VI_FIFO (TX AC Video data packets)
- * RX: UNUSED
- */
- wlc_hw->di[2] = dma_attach(name, wlc_hw->sih,
- DMAREG(wlc_hw, DMA_TX, 2), NULL,
- tune->ntxd, 0, 0, -1, 0, 0,
- &brcm_msg_level);
- dma_attach_err |= (NULL == wlc_hw->di[2]);
- /*
- * FIFO 3
- * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
- * (legacy) TX_CTL_FIFO (TX control & mgmt packets)
- */
- wlc_hw->di[3] = dma_attach(name, wlc_hw->sih,
- DMAREG(wlc_hw, DMA_TX, 3),
- NULL, tune->ntxd, 0, 0, -1,
- 0, 0, &brcm_msg_level);
- dma_attach_err |= (NULL == wlc_hw->di[3]);
-/* Cleaner to leave this as if with AP defined */
-
- if (dma_attach_err) {
- wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed"
- "\n", unit);
- return false;
- }
-
- /* get pointer to dma engine tx flow control variable */
- for (i = 0; i < NFIFO; i++)
- if (wlc_hw->di[i])
- wlc_hw->txavail[i] =
- (uint *) dma_getvar(wlc_hw->di[i],
- "&txavail");
- }
-
- /* initial ucode host flags */
- brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);
-
- return true;
-}
-
-static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)
-{
- uint j;
-
- for (j = 0; j < NFIFO; j++) {
- if (wlc_hw->di[j]) {
- dma_detach(wlc_hw->di[j]);
- wlc_hw->di[j] = NULL;
- }
- }
-}
-
-/* low level attach
- * run backplane attach, init nvram
- * run phy attach
- * initialize software state for each core and band
- * put the whole chip in reset(driver down state), no clock
- */
-int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, uint unit,
- bool piomode, void *regsva, uint bustype, void *btparam)
-{
- struct brcms_hardware *wlc_hw;
- d11regs_t *regs;
- char *macaddr = NULL;
- char *vars;
- uint err = 0;
- uint j;
- bool wme = false;
- struct shared_phy_params sha_params;
- struct wiphy *wiphy = wlc->wiphy;
-
- BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor,
- device);
-
- wme = true;
-
- wlc_hw = wlc->hw;
- wlc_hw->wlc = wlc;
- wlc_hw->unit = unit;
- wlc_hw->band = wlc_hw->bandstate[0];
- wlc_hw->_piomode = piomode;
-
- /* populate struct brcms_hardware with default values */
- brcms_b_info_init(wlc_hw);
-
- /*
- * Do the hardware portion of the attach.
- * Also initialize software state that depends on the particular hardware
- * we are running.
- */
- wlc_hw->sih = ai_attach(regsva, bustype, btparam,
- &wlc_hw->vars, &wlc_hw->vars_size);
- if (wlc_hw->sih == NULL) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
- unit);
- err = 11;
- goto fail;
- }
- vars = wlc_hw->vars;
-
- /*
- * Get vendid/devid nvram overwrites, which could be different
- * than those the BIOS recognizes for devices on PCMCIA_BUS,
- * SDIO_BUS, and SROMless devices on PCI_BUS.
- */
-#ifdef BCMBUSTYPE
- bustype = BCMBUSTYPE;
-#endif
- if (bustype != SI_BUS) {
- char *var;
-
- var = getvar(vars, "vendid");
- if (var) {
- vendor = (u16) simple_strtoul(var, NULL, 0);
- wiphy_err(wiphy, "Overriding vendor id = 0x%x\n",
- vendor);
- }
- var = getvar(vars, "devid");
- if (var) {
- u16 devid = (u16) simple_strtoul(var, NULL, 0);
- if (devid != 0xffff) {
- device = devid;
- wiphy_err(wiphy, "Overriding device id = 0x%x"
- "\n", device);
- }
- }
-
- /* verify again the device is supported */
- if (!brcms_c_chipmatch(vendor, device)) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
- "vendor/device (0x%x/0x%x)\n",
- unit, vendor, device);
- err = 12;
- goto fail;
- }
- }
-
- wlc_hw->vendorid = vendor;
- wlc_hw->deviceid = device;
-
- /* set bar0 window to point at D11 core */
- wlc_hw->regs = (d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
- wlc_hw->corerev = ai_corerev(wlc_hw->sih);
-
- regs = wlc_hw->regs;
-
- wlc->regs = wlc_hw->regs;
-
- /* validate chip, chiprev and corerev */
- if (!brcms_c_isgoodchip(wlc_hw)) {
- err = 13;
- goto fail;
- }
-
- /* initialize power control registers */
- ai_clkctl_init(wlc_hw->sih);
-
- /* request fastclock and force fastclock for the rest of attach
- * bring the d11 core out of reset.
- * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk is still false;
- * But it will be called again inside wlc_corereset, after d11 is out of reset.
- */
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
- brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
-
- if (!brcms_b_validate_chip_access(wlc_hw)) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
- "failed\n", unit);
- err = 14;
- goto fail;
- }
-
- /* get the board rev, used just below */
- j = getintvar(vars, "boardrev");
- /* promote srom boardrev of 0xFF to 1 */
- if (j == BOARDREV_PROMOTABLE)
- j = BOARDREV_PROMOTED;
- wlc_hw->boardrev = (u16) j;
- if (!brcms_c_validboardtype(wlc_hw)) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
- "board type (0x%x)" " or revision level (0x%x)\n",
- unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
- err = 15;
- goto fail;
- }
- wlc_hw->sromrev = (u8) getintvar(vars, "sromrev");
- wlc_hw->boardflags = (u32) getintvar(vars, "boardflags");
- wlc_hw->boardflags2 = (u32) getintvar(vars, "boardflags2");
-
- if (wlc_hw->boardflags & BFL_NOPLLDOWN)
- brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
-
- if ((wlc_hw->sih->bustype == PCI_BUS)
- && (ai_pci_war16165(wlc_hw->sih)))
- wlc->war16165 = true;
-
- /* check device id(srom, nvram etc.) to set bands */
- if (wlc_hw->deviceid == BCM43224_D11N_ID ||
- wlc_hw->deviceid == BCM43224_D11N_ID_VEN1) {
- /* Dualband boards */
- wlc_hw->_nbands = 2;
- } else
- wlc_hw->_nbands = 1;
-
- if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
- wlc_hw->_nbands = 1;
-
- /* BMAC_NOTE: remove init of pub values when brcms_c_attach()
- * unconditionally does the init of these values
- */
- wlc->vendorid = wlc_hw->vendorid;
- wlc->deviceid = wlc_hw->deviceid;
- wlc->pub->sih = wlc_hw->sih;
- wlc->pub->corerev = wlc_hw->corerev;
- wlc->pub->sromrev = wlc_hw->sromrev;
- wlc->pub->boardrev = wlc_hw->boardrev;
- wlc->pub->boardflags = wlc_hw->boardflags;
- wlc->pub->boardflags2 = wlc_hw->boardflags2;
- wlc->pub->_nbands = wlc_hw->_nbands;
-
- wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
-
- if (wlc_hw->physhim == NULL) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
- "failed\n", unit);
- err = 25;
- goto fail;
- }
-
- /* pass all the parameters to wlc_phy_shared_attach in one struct */
- sha_params.sih = wlc_hw->sih;
- sha_params.physhim = wlc_hw->physhim;
- sha_params.unit = unit;
- sha_params.corerev = wlc_hw->corerev;
- sha_params.vars = vars;
- sha_params.vid = wlc_hw->vendorid;
- sha_params.did = wlc_hw->deviceid;
- sha_params.chip = wlc_hw->sih->chip;
- sha_params.chiprev = wlc_hw->sih->chiprev;
- sha_params.chippkg = wlc_hw->sih->chippkg;
- sha_params.sromrev = wlc_hw->sromrev;
- sha_params.boardtype = wlc_hw->sih->boardtype;
- sha_params.boardrev = wlc_hw->boardrev;
- sha_params.boardvendor = wlc_hw->sih->boardvendor;
- sha_params.boardflags = wlc_hw->boardflags;
- sha_params.boardflags2 = wlc_hw->boardflags2;
- sha_params.bustype = wlc_hw->sih->bustype;
- sha_params.buscorerev = wlc_hw->sih->buscorerev;
-
- /* alloc and save pointer to shared phy state area */
- wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
- if (!wlc_hw->phy_sh) {
- err = 16;
- goto fail;
- }
-
- /* initialize software state for each core and band */
- for (j = 0; j < NBANDS_HW(wlc_hw); j++) {
- /*
- * band0 is always 2.4Ghz
- * band1, if present, is 5Ghz
- */
-
- /* So if this is a single band 11a card, use band 1 */
- if (IS_SINGLEBAND_5G(wlc_hw->deviceid))
- j = BAND_5G_INDEX;
-
- brcms_c_setxband(wlc_hw, j);
-
- wlc_hw->band->bandunit = j;
- wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
- wlc->band->bandunit = j;
- wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
- wlc->core->coreidx = ai_coreidx(wlc_hw->sih);
-
- wlc_hw->machwcap = R_REG(&regs->machwcap);
- wlc_hw->machwcap_backup = wlc_hw->machwcap;
-
- /* init tx fifo size */
- wlc_hw->xmtfifo_sz =
- xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
-
- /* Get a phy for this band */
- wlc_hw->band->pi = wlc_phy_attach(wlc_hw->phy_sh,
- (void *)regs, brcms_b_bandtype(wlc_hw), vars,
- wlc->wiphy);
- if (wlc_hw->band->pi == NULL) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
- "attach failed\n", unit);
- err = 17;
- goto fail;
- }
-
- wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
-
- wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
- &wlc_hw->band->phyrev,
- &wlc_hw->band->radioid,
- &wlc_hw->band->radiorev);
- wlc_hw->band->abgphy_encore =
- wlc_phy_get_encore(wlc_hw->band->pi);
- wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
- wlc_hw->band->core_flags =
- wlc_phy_get_coreflags(wlc_hw->band->pi);
-
- /* verify good phy_type & supported phy revision */
- if (BRCMS_ISNPHY(wlc_hw->band)) {
- if (NCONF_HAS(wlc_hw->band->phyrev))
- goto good_phy;
- else
- goto bad_phy;
- } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
- if (LCNCONF_HAS(wlc_hw->band->phyrev))
- goto good_phy;
- else
- goto bad_phy;
- } else {
- bad_phy:
- wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
- "phy type/rev (%d/%d)\n", unit,
- wlc_hw->band->phytype, wlc_hw->band->phyrev);
- err = 18;
- goto fail;
- }
-
- good_phy:
- /* BMAC_NOTE: wlc->band->pi should not be set below and should be done in the
- * high level attach. However we can not make that change until all low level access
- * is changed to wlc_hw->band->pi. Instead do the wlc->band->pi init below, keeping
- * wlc_hw->band->pi as well for incremental update of low level fns, and cut over
- * low only init when all fns updated.
- */
- wlc->band->pi = wlc_hw->band->pi;
- wlc->band->phytype = wlc_hw->band->phytype;
- wlc->band->phyrev = wlc_hw->band->phyrev;
- wlc->band->radioid = wlc_hw->band->radioid;
- wlc->band->radiorev = wlc_hw->band->radiorev;
-
- /* default contention windows size limits */
- wlc_hw->band->CWmin = APHY_CWMIN;
- wlc_hw->band->CWmax = PHY_CWMAX;
-
- if (!brcms_b_attach_dmapio(wlc, j, wme)) {
- err = 19;
- goto fail;
- }
- }
-
- /* disable core to match driver "down" state */
- brcms_c_coredisable(wlc_hw);
-
- /* Match driver "down" state */
- if (wlc_hw->sih->bustype == PCI_BUS)
- ai_pci_down(wlc_hw->sih);
-
- /* register sb interrupt callback functions */
- ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff,
- (void *)brcms_c_wlintrsrestore, NULL, wlc);
-
- /* turn off pll and xtal to match driver "down" state */
- brcms_b_xtal(wlc_hw, OFF);
-
- /* *********************************************************************
- * The hardware is in the DOWN state at this point. D11 core
- * or cores are in reset with clocks off, and the board PLLs
- * are off if possible.
- *
- * Beyond this point, wlc->sbclk == false and chip registers
- * should not be touched.
- *********************************************************************
- */
-
- /* init etheraddr state variables */
- macaddr = brcms_c_get_macaddr(wlc_hw);
- if (macaddr == NULL) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
- unit);
- err = 21;
- goto fail;
- }
- brcmu_ether_atoe(macaddr, wlc_hw->etheraddr);
- if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
- is_zero_ether_addr(wlc_hw->etheraddr)) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
- unit, macaddr);
- err = 22;
- goto fail;
- }
-
- BCMMSG(wlc->wiphy,
- "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
- wlc_hw->deviceid, wlc_hw->_nbands,
- wlc_hw->sih->boardtype, macaddr);
-
- return err;
-
- fail:
- wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
- err);
- return err;
-}
-
-/*
- * Initialize brcms_c_info default values ...
- * may get overrides later in this function
- * BMAC_NOTES, move low out and resolve the dangling ones
- */
-static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
-{
- struct brcms_c_info *wlc = wlc_hw->wlc;
-
- /* set default sw macintmask value */
- wlc->defmacintmask = DEF_MACINTMASK;
-
- /* various 802.11g modes */
- wlc_hw->shortslot = false;
-
- wlc_hw->SFBL = RETRY_SHORT_FB;
- wlc_hw->LFBL = RETRY_LONG_FB;
-
- /* default mac retry limits */
- wlc_hw->SRL = RETRY_SHORT_DEF;
- wlc_hw->LRL = RETRY_LONG_DEF;
- wlc_hw->chanspec = CH20MHZ_CHSPEC(1);
-}
-
-/*
- * low level detach
- */
-int brcms_b_detach(struct brcms_c_info *wlc)
-{
- uint i;
- struct brcms_hw_band *band;
- struct brcms_hardware *wlc_hw = wlc->hw;
- int callbacks;
-
- callbacks = 0;
-
- if (wlc_hw->sih) {
- /* detach interrupt sync mechanism since interrupt is disabled and per-port
- * interrupt object may has been freed. this must be done before sb core switch
- */
- ai_deregister_intr_callback(wlc_hw->sih);
-
- if (wlc_hw->sih->bustype == PCI_BUS)
- ai_pci_sleep(wlc_hw->sih);
- }
-
- brcms_b_detach_dmapio(wlc_hw);
-
- band = wlc_hw->band;
- for (i = 0; i < NBANDS_HW(wlc_hw); i++) {
- if (band->pi) {
- /* Detach this band's phy */
- wlc_phy_detach(band->pi);
- band->pi = NULL;
- }
- band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
- }
-
- /* Free shared phy state */
- kfree(wlc_hw->phy_sh);
-
- wlc_phy_shim_detach(wlc_hw->physhim);
-
- /* free vars */
- kfree(wlc_hw->vars);
- wlc_hw->vars = NULL;
-
- if (wlc_hw->sih) {
- ai_detach(wlc_hw->sih);
- wlc_hw->sih = NULL;
- }
-
- return callbacks;
-
-}
-
-void brcms_b_reset(struct brcms_hardware *wlc_hw)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- /* reset the core */
- if (!DEVICEREMOVED(wlc_hw->wlc))
- brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
-
- /* purge the dma rings */
- brcms_c_flushqueues(wlc_hw->wlc);
-
- brcms_c_reset_bmac_done(wlc_hw->wlc);
-}
-
-void
-brcms_b_init(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
- bool mute) {
- u32 macintmask;
- bool fastclk;
- struct brcms_c_info *wlc = wlc_hw->wlc;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- /* request FAST clock if not on */
- fastclk = wlc_hw->forcefastclk;
- if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- /* disable interrupts */
- macintmask = brcms_intrsoff(wlc->wl);
-
- /* set up the specified band and chanspec */
- brcms_c_setxband(wlc_hw, CHSPEC_BANDUNIT(chanspec));
- wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
-
- /* do one-time phy inits and calibration */
- wlc_phy_cal_init(wlc_hw->band->pi);
-
- /* core-specific initialization */
- brcms_b_coreinit(wlc);
-
- /* suspend the tx fifos and mute the phy for preism cac time */
- if (mute)
- brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
-
- /* band-specific inits */
- brcms_b_bsinit(wlc, chanspec);
-
- /* restore macintmask */
- brcms_intrsrestore(wlc->wl, macintmask);
-
- /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
- * is suspended and brcms_c_enable_mac() will clear this override bit.
- */
- mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
-
- /*
- * initialize mac_suspend_depth to 1 to match ucode initial suspended state
- */
- wlc_hw->mac_suspend_depth = 1;
-
- /* restore the clk */
- if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
-}
-
-int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
-{
- uint coremask;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- /*
- * Enable pll and xtal, initialize the power control registers,
- * and force fastclock for the remainder of brcms_c_up().
- */
- brcms_b_xtal(wlc_hw, ON);
- ai_clkctl_init(wlc_hw->sih);
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- /*
- * Configure pci/pcmcia here instead of in brcms_c_attach()
- * to allow mfg hotswap: down, hotswap (chip power cycle), up.
- */
- coremask = (1 << wlc_hw->wlc->core->coreidx);
-
- if (wlc_hw->sih->bustype == PCI_BUS)
- ai_pci_setup(wlc_hw->sih, coremask);
-
- /*
- * Need to read the hwradio status here to cover the case where the system
- * is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
- */
- if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
- /* put SB PCI in down state again */
- if (wlc_hw->sih->bustype == PCI_BUS)
- ai_pci_down(wlc_hw->sih);
- brcms_b_xtal(wlc_hw, OFF);
- return -ENOMEDIUM;
- }
-
- if (wlc_hw->sih->bustype == PCI_BUS)
- ai_pci_up(wlc_hw->sih);
-
- /* reset the d11 core */
- brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
-
- return 0;
-}
-
-int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- wlc_hw->up = true;
- wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
-
- /* FULLY enable dynamic power control and d11 core interrupt */
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
- brcms_intrson(wlc_hw->wlc->wl);
- return 0;
-}
-
-int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
-{
- bool dev_gone;
- uint callbacks = 0;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- if (!wlc_hw->up)
- return callbacks;
-
- dev_gone = DEVICEREMOVED(wlc_hw->wlc);
-
- /* disable interrupts */
- if (dev_gone)
- wlc_hw->wlc->macintmask = 0;
- else {
- /* now disable interrupts */
- brcms_intrsoff(wlc_hw->wlc->wl);
-
- /* ensure we're running on the pll clock again */
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
- }
- /* down phy at the last of this stage */
- callbacks += wlc_phy_down(wlc_hw->band->pi);
-
- return callbacks;
-}
-
-int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
-{
- uint callbacks = 0;
- bool dev_gone;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- if (!wlc_hw->up)
- return callbacks;
-
- wlc_hw->up = false;
- wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
-
- dev_gone = DEVICEREMOVED(wlc_hw->wlc);
-
- if (dev_gone) {
- wlc_hw->sbclk = false;
- wlc_hw->clk = false;
- wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
-
- /* reclaim any posted packets */
- brcms_c_flushqueues(wlc_hw->wlc);
- } else {
-
- /* Reset and disable the core */
- if (ai_iscoreup(wlc_hw->sih)) {
- if (R_REG(&wlc_hw->regs->maccontrol) &
- MCTL_EN_MAC)
- brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
- callbacks += brcms_reset(wlc_hw->wlc->wl);
- brcms_c_coredisable(wlc_hw);
- }
-
- /* turn off primary xtal and pll */
- if (!wlc_hw->noreset) {
- if (wlc_hw->sih->bustype == PCI_BUS)
- ai_pci_down(wlc_hw->sih);
- brcms_b_xtal(wlc_hw, OFF);
- }
- }
-
- return callbacks;
-}
-
-void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
-{
- /* delay before first read of ucode state */
- udelay(40);
-
- /* wait until ucode is no longer asleep */
- SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
- DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
-}
-
-void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw, u8 *ea)
-{
- memcpy(ea, wlc_hw->etheraddr, ETH_ALEN);
-}
-
-static int brcms_b_bandtype(struct brcms_hardware *wlc_hw)
-{
- return wlc_hw->band->bandtype;
-}
-
-/* control chip clock to save power, enable dynamic clock or force fast clock */
-static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
-{
- if (PMUCTL_ENAB(wlc_hw->sih)) {
- /* new chips with PMU, CCS_FORCEHT will distribute the HT clock on backplane,
- * but mac core will still run on ALP(not HT) when it enters powersave mode,
- * which means the FCA bit may not be set.
- * should wakeup mac if driver wants it to run on HT.
- */
-
- if (wlc_hw->clk) {
- if (mode == CLK_FAST) {
- OR_REG(&wlc_hw->regs->clk_ctl_st,
- CCS_FORCEHT);
-
- udelay(64);
-
- SPINWAIT(((R_REG
- (&wlc_hw->regs->
- clk_ctl_st) & CCS_HTAVAIL) == 0),
- PMU_MAX_TRANSITION_DLY);
- WARN_ON(!(R_REG
- (&wlc_hw->regs->
- clk_ctl_st) & CCS_HTAVAIL));
- } else {
- if ((wlc_hw->sih->pmurev == 0) &&
- (R_REG
- (&wlc_hw->regs->
- clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ)))
- SPINWAIT(((R_REG
- (&wlc_hw->regs->
- clk_ctl_st) & CCS_HTAVAIL)
- == 0),
- PMU_MAX_TRANSITION_DLY);
- AND_REG(&wlc_hw->regs->clk_ctl_st,
- ~CCS_FORCEHT);
- }
- }
- wlc_hw->forcefastclk = (mode == CLK_FAST);
- } else {
-
- /* old chips w/o PMU, force HT through cc,
- * then use FCA to verify mac is running fast clock
- */
-
- wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode);
-
- /* check fast clock is available (if core is not in reset) */
- if (wlc_hw->forcefastclk && wlc_hw->clk)
- WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) &
- SISF_FCLKA));
-
- /* keep the ucode wake bit on if forcefastclk is on
- * since we do not want ucode to put us back to slow clock
- * when it dozes for PM mode.
- * Code below matches the wake override bit with current forcefastclk state
- * Only setting bit in wake_override instead of waking ucode immediately
- * since old code (wlc.c 1.4499) had this behavior. Older code set
- * wlc->forcefastclk but only had the wake happen if the wakup_ucode work
- * (protected by an up check) was executed just below.
- */
- if (wlc_hw->forcefastclk)
- mboolset(wlc_hw->wake_override,
- BRCMS_WAKE_OVERRIDE_FORCEFAST);
- else
- mboolclr(wlc_hw->wake_override,
- BRCMS_WAKE_OVERRIDE_FORCEFAST);
- }
-}
-
-/* set initial host flags value */
-static void
-brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
-
- memset(mhfs, 0, MHFMAX * sizeof(u16));
-
- mhfs[MHF2] |= mhf2_init;
-
- /* prohibit use of slowclock on multifunction boards */
- if (wlc_hw->boardflags & BFL_NOPLLDOWN)
- mhfs[MHF1] |= MHF1_FORCEFASTCLK;
-
- if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
- mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
- mhfs[MHF1] |= MHF1_IQSWAP_WAR;
- }
-}
-
-/* set or clear ucode host flag bits
- * it has an optimization for no-change write
- * it only writes through shared memory when the core has clock;
- * pre-CLK changes should use wlc_write_mhf to get around the optimization
- *
- *
- * bands values are: BRCM_BAND_AUTO <--- Current band only
- * BRCM_BAND_5G <--- 5G band only
- * BRCM_BAND_2G <--- 2G band only
- * BRCM_BAND_ALL <--- All bands
- */
-void
-brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
- int bands)
-{
- u16 save;
- u16 addr[MHFMAX] = {
- M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
- M_HOST_FLAGS5
- };
- struct brcms_hw_band *band;
-
- if ((val & ~mask) || idx >= MHFMAX)
- return; /* error condition */
-
- switch (bands) {
- /* Current band only or all bands,
- * then set the band to current band
- */
- case BRCM_BAND_AUTO:
- case BRCM_BAND_ALL:
- band = wlc_hw->band;
- break;
- case BRCM_BAND_5G:
- band = wlc_hw->bandstate[BAND_5G_INDEX];
- break;
- case BRCM_BAND_2G:
- band = wlc_hw->bandstate[BAND_2G_INDEX];
- break;
- default:
- band = NULL; /* error condition */
- }
-
- if (band) {
- save = band->mhfs[idx];
- band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;
-
- /* optimization: only write through if changed, and
- * changed band is the current band
- */
- if (wlc_hw->clk && (band->mhfs[idx] != save)
- && (band == wlc_hw->band))
- brcms_b_write_shm(wlc_hw, addr[idx],
- (u16) band->mhfs[idx]);
- }
-
- if (bands == BRCM_BAND_ALL) {
- wlc_hw->bandstate[0]->mhfs[idx] =
- (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;
- wlc_hw->bandstate[1]->mhfs[idx] =
- (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;
- }
-}
-
-u16 brcms_b_mhf_get(struct brcms_hardware *wlc_hw, u8 idx, int bands)
-{
- struct brcms_hw_band *band;
-
- if (idx >= MHFMAX)
- return 0; /* error condition */
- switch (bands) {
- case BRCM_BAND_AUTO:
- band = wlc_hw->band;
- break;
- case BRCM_BAND_5G:
- band = wlc_hw->bandstate[BAND_5G_INDEX];
- break;
- case BRCM_BAND_2G:
- band = wlc_hw->bandstate[BAND_2G_INDEX];
- break;
- default:
- band = NULL; /* error condition */
- }
-
- if (!band)
- return 0;
-
- return band->mhfs[idx];
-}
-
-static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
-{
- u8 idx;
- u16 addr[] = {
- M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
- M_HOST_FLAGS5
- };
-
- for (idx = 0; idx < MHFMAX; idx++) {
- brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
- }
-}
-
-/* set the maccontrol register to desired reset state and
- * initialize the sw cache of the register
- */
-static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)
-{
- /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
- wlc_hw->maccontrol = 0;
- wlc_hw->suspended_fifos = 0;
- wlc_hw->wake_override = 0;
- wlc_hw->mute_override = 0;
- brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
-}
-
-/* set or clear maccontrol bits */
-void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
-{
- u32 maccontrol;
- u32 new_maccontrol;
-
- if (val & ~mask)
- return; /* error condition */
- maccontrol = wlc_hw->maccontrol;
- new_maccontrol = (maccontrol & ~mask) | val;
-
- /* if the new maccontrol value is the same as the old, nothing to do */
- if (new_maccontrol == maccontrol)
- return;
-
- /* something changed, cache the new value */
- wlc_hw->maccontrol = new_maccontrol;
-
- /* write the new values with overrides applied */
- brcms_c_mctrl_write(wlc_hw);
-}
-
-/* write the software state of maccontrol and overrides to the maccontrol register */
-static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
-{
- u32 maccontrol = wlc_hw->maccontrol;
-
- /* OR in the wake bit if overridden */
- if (wlc_hw->wake_override)
- maccontrol |= MCTL_WAKE;
-
- /* set AP and INFRA bits for mute if needed */
- if (wlc_hw->mute_override) {
- maccontrol &= ~(MCTL_AP);
- maccontrol |= MCTL_INFRA;
- }
-
- W_REG(&wlc_hw->regs->maccontrol, maccontrol);
-}
-
-void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
- u32 override_bit)
-{
- if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {
- mboolset(wlc_hw->wake_override, override_bit);
- return;
- }
-
- mboolset(wlc_hw->wake_override, override_bit);
-
- brcms_c_mctrl_write(wlc_hw);
- brcms_b_wait_for_wake(wlc_hw);
-
- return;
-}
-
-void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
- u32 override_bit)
-{
- mboolclr(wlc_hw->wake_override, override_bit);
-
- if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))
- return;
-
- brcms_c_mctrl_write(wlc_hw);
-
- return;
-}
-
-/* When driver needs ucode to stop beaconing, it has to make sure that
- * MCTL_AP is clear and MCTL_INFRA is set
- * Mode MCTL_AP MCTL_INFRA
- * AP 1 1
- * STA 0 1 <--- This will ensure no beacons
- * IBSS 0 0
- */
-static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw)
-{
- wlc_hw->mute_override = 1;
-
- /* if maccontrol already has AP == 0 and INFRA == 1 without this
- * override, then there is no change to write
- */
- if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
- return;
-
- brcms_c_mctrl_write(wlc_hw);
-
- return;
-}
-
-/* Clear the override on AP and INFRA bits */
-static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw)
-{
- if (wlc_hw->mute_override == 0)
- return;
-
- wlc_hw->mute_override = 0;
-
- /* if maccontrol already has AP == 0 and INFRA == 1 without this
- * override, then there is no change to write
- */
- if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
- return;
-
- brcms_c_mctrl_write(wlc_hw);
-}
-
-/*
- * Write a MAC address to the given match reg offset in the RXE match engine.
- */
-void
-brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,
- const u8 *addr)
-{
- d11regs_t *regs;
- u16 mac_l;
- u16 mac_m;
- u16 mac_h;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n",
- wlc_hw->unit);
-
- regs = wlc_hw->regs;
- mac_l = addr[0] | (addr[1] << 8);
- mac_m = addr[2] | (addr[3] << 8);
- mac_h = addr[4] | (addr[5] << 8);
-
- /* enter the MAC addr into the RXE match registers */
- W_REG(&regs->rcm_ctl, RCM_INC_DATA | match_reg_offset);
- W_REG(&regs->rcm_mat_data, mac_l);
- W_REG(&regs->rcm_mat_data, mac_m);
- W_REG(&regs->rcm_mat_data, mac_h);
-
-}
-
-void
-brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,
- void *buf)
-{
- d11regs_t *regs;
- u32 word;
- bool be_bit;
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- regs = wlc_hw->regs;
- W_REG(&regs->tplatewrptr, offset);
-
- /* if MCTL_BIGEND bit set in mac control register,
- * the chip swaps data in fifo, as well as data in
- * template ram
- */
- be_bit = (R_REG(&regs->maccontrol) & MCTL_BIGEND) != 0;
-
- while (len > 0) {
- memcpy(&word, buf, sizeof(u32));
-
- if (be_bit)
- word = cpu_to_be32(word);
- else
- word = cpu_to_le32(word);
-
- W_REG(&regs->tplatewrdata, word);
-
- buf = (u8 *) buf + sizeof(u32);
- len -= sizeof(u32);
- }
-}
-
-void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin)
-{
- wlc_hw->band->CWmin = newmin;
-
- W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN);
- (void)R_REG(&wlc_hw->regs->objaddr);
- W_REG(&wlc_hw->regs->objdata, newmin);
-}
-
-void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax)
-{
- wlc_hw->band->CWmax = newmax;
-
- W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX);
- (void)R_REG(&wlc_hw->regs->objaddr);
- W_REG(&wlc_hw->regs->objdata, newmax);
-}
-
-void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
-{
- bool fastclk;
-
- /* request FAST clock if not on */
- fastclk = wlc_hw->forcefastclk;
- if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
-
- brcms_b_phy_reset(wlc_hw);
- wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));
-
- /* restore the clk */
- if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
-}
-
-static void
-brcms_c_write_hw_bcntemplate0(struct brcms_hardware *wlc_hw, void *bcn,
- int len)
-{
- d11regs_t *regs = wlc_hw->regs;
-
- brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE, (len + 3) & ~3,
- bcn);
- /* write beacon length to SCR */
- brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
- /* mark beacon0 valid */
- OR_REG(&regs->maccommand, MCMD_BCN0VLD);
-}
-
-static void
-brcms_c_write_hw_bcntemplate1(struct brcms_hardware *wlc_hw, void *bcn,
- int len)
-{
- d11regs_t *regs = wlc_hw->regs;
-
- brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE, (len + 3) & ~3,
- bcn);
- /* write beacon length to SCR */
- brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
- /* mark beacon1 valid */
- OR_REG(&regs->maccommand, MCMD_BCN1VLD);
-}
-
-/* mac is assumed to be suspended at this point */
-void
-brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw, void *bcn,
- int len, bool both)
-{
- d11regs_t *regs = wlc_hw->regs;
-
- if (both) {
- brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len);
- brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len);
- } else {
- /* bcn 0 */
- if (!(R_REG(&regs->maccommand) & MCMD_BCN0VLD))
- brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len);
- /* bcn 1 */
- else if (!
- (R_REG(&regs->maccommand) & MCMD_BCN1VLD))
- brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len);
- }
-}
-
-static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
-{
- u16 v;
- struct brcms_c_info *wlc = wlc_hw->wlc;
- /* update SYNTHPU_DLY */
-
- if (BRCMS_ISLCNPHY(wlc->band)) {
- v = SYNTHPU_DLY_LPPHY_US;
- } else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3))) {
- v = SYNTHPU_DLY_NPHY_US;
- } else {
- v = SYNTHPU_DLY_BPHY_US;
- }
-
- brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
-}
-
-/* band-specific init */
-static void
-brcms_b_bsinit(struct brcms_c_info *wlc, chanspec_t chanspec)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
-
- BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
- wlc_hw->band->bandunit);
-
- brcms_c_ucode_bsinit(wlc_hw);
-
- wlc_phy_init(wlc_hw->band->pi, chanspec);
-
- brcms_c_ucode_txant_set(wlc_hw);
-
- /* cwmin is band-specific, update hardware with value for current band */
- brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
- brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
-
- brcms_b_update_slot_timing(wlc_hw,
- BAND_5G(wlc_hw->band->
- bandtype) ? true : wlc_hw->
- shortslot);
-
- /* write phytype and phyvers */
- brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);
- brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);
-
- /* initialize the txphyctl1 rate table since shmem is shared between bands */
- brcms_upd_ofdm_pctl1_table(wlc_hw);
-
- brcms_b_upd_synthpu(wlc_hw);
-}
-
-static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
-
- wlc_hw->phyclk = clk;
-
- if (OFF == clk) { /* clear gmode bit, put phy into reset */
-
- ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE),
- (SICF_PRST | SICF_FGC));
- udelay(1);
- ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST);
- udelay(1);
-
- } else { /* take phy out of reset */
-
- ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC);
- udelay(1);
- ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0);
- udelay(1);
-
- }
-}
-
-/* Perform a soft reset of the PHY PLL */
-void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- ai_corereg(wlc_hw->sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_addr), ~0, 0);
- udelay(1);
- ai_corereg(wlc_hw->sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_data), 0x4, 0);
- udelay(1);
- ai_corereg(wlc_hw->sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_data), 0x4, 4);
- udelay(1);
- ai_corereg(wlc_hw->sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_data), 0x4, 0);
- udelay(1);
-}
-
-/* light way to turn on phy clock without reset for NPHY only
- * refer to brcms_b_core_phy_clk for full version
- */
-void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk)
-{
- /* support(necessary for NPHY and HYPHY) only */
- if (!BRCMS_ISNPHY(wlc_hw->band))
- return;
-
- if (ON == clk)
- ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC);
- else
- ai_core_cflags(wlc_hw->sih, SICF_FGC, 0);
-
-}
-
-void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk)
-{
- if (ON == clk)
- ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE);
- else
- ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0);
-}
-
-void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)
-{
- struct brcms_phy_pub *pih = wlc_hw->band->pi;
- u32 phy_bw_clkbits;
- bool phy_in_reset = false;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- if (pih == NULL)
- return;
-
- phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);
-
- /* Specific reset sequence required for NPHY rev 3 and 4 */
- if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&
- NREV_LE(wlc_hw->band->phyrev, 4)) {
- /* Set the PHY bandwidth */
- ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits);
-
- udelay(1);
-
- /* Perform a soft reset of the PHY PLL */
- brcms_b_core_phypll_reset(wlc_hw);
-
- /* reset the PHY */
- ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE),
- (SICF_PRST | SICF_PCLKE));
- phy_in_reset = true;
- } else {
-
- ai_core_cflags(wlc_hw->sih,
- (SICF_PRST | SICF_PCLKE | SICF_BWMASK),
- (SICF_PRST | SICF_PCLKE | phy_bw_clkbits));
- }
-
- udelay(2);
- brcms_b_core_phy_clk(wlc_hw, ON);
-
- if (pih)
- wlc_phy_anacore(pih, ON);
-}
-
-/* switch to and initialize new band */
-static void
-brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
- chanspec_t chanspec) {
- struct brcms_c_info *wlc = wlc_hw->wlc;
- u32 macintmask;
-
- /* Enable the d11 core before accessing it */
- if (!ai_iscoreup(wlc_hw->sih)) {
- ai_core_reset(wlc_hw->sih, 0, 0);
- brcms_c_mctrl_reset(wlc_hw);
- }
-
- macintmask = brcms_c_setband_inact(wlc, bandunit);
-
- if (!wlc_hw->up)
- return;
-
- brcms_b_core_phy_clk(wlc_hw, ON);
-
- /* band-specific initializations */
- brcms_b_bsinit(wlc, chanspec);
-
- /*
- * If there are any pending software interrupt bits,
- * then replace these with a harmless nonzero value
- * so brcms_c_dpc() will re-enable interrupts when done.
- */
- if (wlc->macintstatus)
- wlc->macintstatus = MI_DMAINT;
-
- /* restore macintmask */
- brcms_intrsrestore(wlc->wl, macintmask);
-
- /* ucode should still be suspended.. */
- WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
-}
-
-/* low-level band switch utility routine */
-void brcms_c_setxband(struct brcms_hardware *wlc_hw,
- uint bandunit)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
- bandunit);
-
- wlc_hw->band = wlc_hw->bandstate[bandunit];
-
- /* BMAC_NOTE: until we eliminate need for wlc->band refs in low level code */
- wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
-
- /* set gmode core flag */
- if (wlc_hw->sbclk && !wlc_hw->noreset) {
- ai_core_cflags(wlc_hw->sih, SICF_GMODE,
- ((bandunit == 0) ? SICF_GMODE : 0));
- }
-}
-
-static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)
-{
-
- /* reject unsupported corerev */
- if (!VALID_COREREV(wlc_hw->corerev)) {
- wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n",
- wlc_hw->corerev);
- return false;
- }
-
- return true;
-}
-
-/* Validate some board info parameters */
-static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
-{
- uint boardrev = wlc_hw->boardrev;
-
- /* 4 bits each for board type, major, minor, and tiny version */
- uint brt = (boardrev & 0xf000) >> 12;
- uint b0 = (boardrev & 0xf00) >> 8;
- uint b1 = (boardrev & 0xf0) >> 4;
- uint b2 = boardrev & 0xf;
-
- /* voards from other vendors are always considered valid */
- if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM)
- return true;
-
- /* do some boardrev sanity checks when boardvendor is Broadcom */
- if (boardrev == 0)
- return false;
-
- if (boardrev <= 0xff)
- return true;
-
- if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)
- || (b2 > 9))
- return false;
-
- return true;
-}
-
-static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
-{
- const char *varname = "macaddr";
- char *macaddr;
-
- /* If macaddr exists, use it (Sromrev4, CIS, ...). */
- macaddr = getvar(wlc_hw->vars, varname);
- if (macaddr != NULL)
- return macaddr;
-
- if (NBANDS_HW(wlc_hw) > 1)
- varname = "et1macaddr";
- else
- varname = "il0macaddr";
-
- macaddr = getvar(wlc_hw->vars, varname);
- if (macaddr == NULL) {
- wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
- "getvar(%s) not found\n", wlc_hw->unit, varname);
- }
-
- return macaddr;
-}
-
-/*
- * Return true if radio is disabled, otherwise false.
- * hw radio disable signal is an external pin, users activate it asynchronously
- * this function could be called when driver is down and w/o clock
- * it operates on different registers depending on corerev and boardflag.
- */
-bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)
-{
- bool v, clk, xtal;
- u32 resetbits = 0, flags = 0;
-
- xtal = wlc_hw->sbclk;
- if (!xtal)
- brcms_b_xtal(wlc_hw, ON);
-
- /* may need to take core out of reset first */
- clk = wlc_hw->clk;
- if (!clk) {
- /*
- * mac no longer enables phyclk automatically when driver
- * accesses phyreg throughput mac. This can be skipped since
- * only mac reg is accessed below
- */
- flags |= SICF_PCLKE;
-
- /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
- if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
- (wlc_hw->sih->chip == BCM43225_CHIP_ID))
- wlc_hw->regs =
- (d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID,
- 0);
- ai_core_reset(wlc_hw->sih, flags, resetbits);
- brcms_c_mctrl_reset(wlc_hw);
- }
-
- v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0);
-
- /* put core back into reset */
- if (!clk)
- ai_core_disable(wlc_hw->sih, 0);
-
- if (!xtal)
- brcms_b_xtal(wlc_hw, OFF);
-
- return v;
-}
-
-/* Initialize just the hardware when coming out of POR or S3/S5 system states */
-void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
-{
- if (wlc_hw->wlc->pub->hw_up)
- return;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- /*
- * Enable pll and xtal, initialize the power control registers,
- * and force fastclock for the remainder of brcms_c_up().
- */
- brcms_b_xtal(wlc_hw, ON);
- ai_clkctl_init(wlc_hw->sih);
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- if (wlc_hw->sih->bustype == PCI_BUS) {
- ai_pci_fixcfg(wlc_hw->sih);
-
- /* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
- if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
- (wlc_hw->sih->chip == BCM43225_CHIP_ID))
- wlc_hw->regs =
- (d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID,
- 0);
- }
-
- /* Inform phy that a POR reset has occurred so it does a complete phy init */
- wlc_phy_por_inform(wlc_hw->band->pi);
-
- wlc_hw->ucode_loaded = false;
- wlc_hw->wlc->pub->hw_up = true;
-
- if ((wlc_hw->boardflags & BFL_FEM)
- && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
- if (!
- (wlc_hw->boardrev >= 0x1250
- && (wlc_hw->boardflags & BFL_FEM_BT)))
- ai_epa_4313war(wlc_hw->sih);
- }
-}
-
-static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)
-{
- struct dma_pub *di = wlc_hw->di[fifo];
- return dma_rxreset(di);
-}
-
-/* d11 core reset
- * ensure fask clock during reset
- * reset dma
- * reset d11(out of reset)
- * reset phy(out of reset)
- * clear software macintstatus for fresh new start
- * one testing hack wlc_hw->noreset will bypass the d11/phy reset
- */
-void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
-{
- d11regs_t *regs;
- uint i;
- bool fastclk;
- u32 resetbits = 0;
-
- if (flags == BRCMS_USE_COREFLAGS)
- flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- regs = wlc_hw->regs;
-
- /* request FAST clock if not on */
- fastclk = wlc_hw->forcefastclk;
- if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- /* reset the dma engines except first time thru */
- if (ai_iscoreup(wlc_hw->sih)) {
- for (i = 0; i < NFIFO; i++)
- if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) {
- wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: "
- "dma_txreset[%d]: cannot stop dma\n",
- wlc_hw->unit, __func__, i);
- }
-
- if ((wlc_hw->di[RX_FIFO])
- && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) {
- wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset"
- "[%d]: cannot stop dma\n",
- wlc_hw->unit, __func__, RX_FIFO);
- }
- }
- /* if noreset, just stop the psm and return */
- if (wlc_hw->noreset) {
- wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */
- brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);
- return;
- }
-
- /*
- * mac no longer enables phyclk automatically when driver accesses
- * phyreg throughput mac, AND phy_reset is skipped at early stage when
- * band->pi is invalid. need to enable PHY CLK
- */
- flags |= SICF_PCLKE;
-
- /* reset the core
- * In chips with PMU, the fastclk request goes through d11 core reg 0x1e0, which
- * is cleared by the core_reset. have to re-request it.
- * This adds some delay and we can optimize it by also requesting fastclk through
- * chipcommon during this period if necessary. But that has to work coordinate
- * with other driver like mips/arm since they may touch chipcommon as well.
- */
- wlc_hw->clk = false;
- ai_core_reset(wlc_hw->sih, flags, resetbits);
- wlc_hw->clk = true;
- if (wlc_hw->band && wlc_hw->band->pi)
- wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);
-
- brcms_c_mctrl_reset(wlc_hw);
-
- if (PMUCTL_ENAB(wlc_hw->sih))
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- brcms_b_phy_reset(wlc_hw);
-
- /* turn on PHY_PLL */
- brcms_b_core_phypll_ctl(wlc_hw, true);
-
- /* clear sw intstatus */
- wlc_hw->wlc->macintstatus = 0;
-
- /* restore the clk setting */
- if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
-}
-
-/* txfifo sizes needs to be modified(increased) since the newer cores
- * have more memory.
- */
-static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)
-{
- d11regs_t *regs = wlc_hw->regs;
- u16 fifo_nu;
- u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
- u16 txfifo_def, txfifo_def1;
- u16 txfifo_cmd;
-
- /* tx fifos start at TXFIFO_START_BLK from the Base address */
- txfifo_startblk = TXFIFO_START_BLK;
-
- /* sequence of operations: reset fifo, set fifo size, reset fifo */
- for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
-
- txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
- txfifo_def = (txfifo_startblk & 0xff) |
- (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
- txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
- ((((txfifo_endblk -
- 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
- txfifo_cmd =
- TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
-
- W_REG(&regs->xmtfifocmd, txfifo_cmd);
- W_REG(&regs->xmtfifodef, txfifo_def);
- W_REG(&regs->xmtfifodef1, txfifo_def1);
-
- W_REG(&regs->xmtfifocmd, txfifo_cmd);
-
- txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
- }
- /*
- * need to propagate to shm location to be in sync since ucode/hw won't
- * do this
- */
- brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
- wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
- brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
- wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
- brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
- ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
- xmtfifo_sz[TX_AC_BK_FIFO]));
- brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
- ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
- xmtfifo_sz[TX_BCMC_FIFO]));
-}
-
-/* d11 core init
- * reset PSM
- * download ucode/PCM
- * let ucode run to suspended
- * download ucode inits
- * config other core registers
- * init dma
- */
-static void brcms_b_coreinit(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- d11regs_t *regs;
- u32 sflags;
- uint bcnint_us;
- uint i = 0;
- bool fifosz_fixup = false;
- int err = 0;
- u16 buf[NFIFO];
- struct wiphy *wiphy = wlc->wiphy;
-
- regs = wlc_hw->regs;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- /* reset PSM */
- brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
-
- brcms_ucode_download(wlc_hw);
- /*
- * FIFOSZ fixup. driver wants to controls the fifo allocation.
- */
- fifosz_fixup = true;
-
- /* let the PSM run to the suspended state, set mode to BSS STA */
- W_REG(&regs->macintstatus, -1);
- brcms_b_mctrl(wlc_hw, ~0,
- (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
-
- /* wait for ucode to self-suspend after auto-init */
- SPINWAIT(((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0),
- 1000 * 1000);
- if ((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0)
- wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
- "suspend!\n", wlc_hw->unit);
-
- brcms_c_gpio_init(wlc);
-
- sflags = ai_core_sflags(wlc_hw->sih, 0, 0);
-
- if (D11REV_IS(wlc_hw->corerev, 23)) {
- if (BRCMS_ISNPHY(wlc_hw->band))
- brcms_c_write_inits(wlc_hw, d11n0initvals16);
- else
- wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
- " %d\n", __func__, wlc_hw->unit,
- wlc_hw->corerev);
- } else if (D11REV_IS(wlc_hw->corerev, 24)) {
- if (BRCMS_ISLCNPHY(wlc_hw->band)) {
- brcms_c_write_inits(wlc_hw, d11lcn0initvals24);
- } else {
- wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
- " %d\n", __func__, wlc_hw->unit,
- wlc_hw->corerev);
- }
- } else {
- wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev);
- }
-
- /* For old ucode, txfifo sizes needs to be modified(increased) */
- if (fifosz_fixup == true) {
- brcms_b_corerev_fifofixup(wlc_hw);
- }
-
- /* check txfifo allocations match between ucode and driver */
- buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
- if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
- i = TX_AC_BE_FIFO;
- err = -1;
- }
- buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
- if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
- i = TX_AC_VI_FIFO;
- err = -1;
- }
- buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
- buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
- buf[TX_AC_BK_FIFO] &= 0xff;
- if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
- i = TX_AC_BK_FIFO;
- err = -1;
- }
- if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
- i = TX_AC_VO_FIFO;
- err = -1;
- }
- buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
- buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
- buf[TX_BCMC_FIFO] &= 0xff;
- if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
- i = TX_BCMC_FIFO;
- err = -1;
- }
- if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
- i = TX_ATIM_FIFO;
- err = -1;
- }
- if (err != 0) {
- wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
- " driver size %d index %d\n", buf[i],
- wlc_hw->xmtfifo_sz[i], i);
- }
-
- /* make sure we can still talk to the mac */
- WARN_ON(R_REG(&regs->maccontrol) == 0xffffffff);
-
- /* band-specific inits done by wlc_bsinit() */
-
- /* Set up frame burst size and antenna swap threshold init values */
- brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
- brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
-
- /* enable one rx interrupt per received frame */
- W_REG(&regs->intrcvlazy[0], (1 << IRL_FC_SHIFT));
-
- /* set the station mode (BSS STA) */
- brcms_b_mctrl(wlc_hw,
- (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
- (MCTL_INFRA | MCTL_DISCARD_PMQ));
-
- /* set up Beacon interval */
- bcnint_us = 0x8000 << 10;
- W_REG(&regs->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT));
- W_REG(&regs->tsf_cfpstart, bcnint_us);
- W_REG(&regs->macintstatus, MI_GP1);
-
- /* write interrupt mask */
- W_REG(&regs->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK);
-
- /* allow the MAC to control the PHY clock (dynamic on/off) */
- brcms_b_macphyclk_set(wlc_hw, ON);
-
- /* program dynamic clock control fast powerup delay register */
- wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
- W_REG(&regs->scc_fastpwrup_dly, wlc->fastpwrup_dly);
-
- /* tell the ucode the corerev */
- brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
-
- /* tell the ucode MAC capabilities */
- brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
- (u16) (wlc_hw->machwcap & 0xffff));
- brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
- (u16) ((wlc_hw->
- machwcap >> 16) & 0xffff));
-
- /* write retry limits to SCR, this done after PSM init */
- W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
- (void)R_REG(&regs->objaddr);
- W_REG(&regs->objdata, wlc_hw->SRL);
- W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
- (void)R_REG(&regs->objaddr);
- W_REG(&regs->objdata, wlc_hw->LRL);
-
- /* write rate fallback retry limits */
- brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
- brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
-
- AND_REG(&regs->ifs_ctl, 0x0FFF);
- W_REG(&regs->ifs_aifsn, EDCF_AIFSN_MIN);
-
- /* dma initializations */
- wlc->txpend16165war = 0;
-
- /* init the tx dma engines */
- for (i = 0; i < NFIFO; i++) {
- if (wlc_hw->di[i])
- dma_txinit(wlc_hw->di[i]);
- }
-
- /* init the rx dma engine(s) and post receive buffers */
- dma_rxinit(wlc_hw->di[RX_FIFO]);
- dma_rxfill(wlc_hw->di[RX_FIFO]);
-}
-
-/* This function is used for changing the tsf frac register
- * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
- * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
- * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
- * HTPHY Formula is 2^26/freq(MHz) e.g.
- * For spuron2 - 126MHz -> 2^26/126 = 532610.0
- * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
- * For spuron: 123MHz -> 2^26/123 = 545600.5
- * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
- * For spur off: 120MHz -> 2^26/120 = 559240.5
- * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
- */
-
-void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
-{
- d11regs_t *regs;
- regs = wlc_hw->regs;
-
- if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
- (wlc_hw->sih->chip == BCM43225_CHIP_ID)) {
- if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */
- W_REG(&regs->tsf_clk_frac_l, 0x2082);
- W_REG(&regs->tsf_clk_frac_h, 0x8);
- } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */
- W_REG(&regs->tsf_clk_frac_l, 0x5341);
- W_REG(&regs->tsf_clk_frac_h, 0x8);
- } else { /* 120Mhz */
- W_REG(&regs->tsf_clk_frac_l, 0x8889);
- W_REG(&regs->tsf_clk_frac_h, 0x8);
- }
- } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
- if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */
- W_REG(&regs->tsf_clk_frac_l, 0x7CE0);
- W_REG(&regs->tsf_clk_frac_h, 0xC);
- } else { /* 80Mhz */
- W_REG(&regs->tsf_clk_frac_l, 0xCCCD);
- W_REG(&regs->tsf_clk_frac_h, 0xC);
- }
- }
-}
-
-/* Initialize GPIOs that are controlled by D11 core */
-static void brcms_c_gpio_init(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- d11regs_t *regs;
- u32 gc, gm;
-
- regs = wlc_hw->regs;
-
- /* use GPIO select 0 to get all gpio signals from the gpio out reg */
- brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);
-
- /*
- * Common GPIO setup:
- * G0 = LED 0 = WLAN Activity
- * G1 = LED 1 = WLAN 2.4 GHz Radio State
- * G2 = LED 2 = WLAN 5 GHz Radio State
- * G4 = radio disable input (HI enabled, LO disabled)
- */
-
- gc = gm = 0;
-
- /* Allocate GPIOs for mimo antenna diversity feature */
- if (wlc_hw->antsel_type == ANTSEL_2x3) {
- /* Enable antenna diversity, use 2x3 mode */
- brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
- MHF3_ANTSEL_EN, BRCM_BAND_ALL);
- brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,
- MHF3_ANTSEL_MODE, BRCM_BAND_ALL);
-
- /* init superswitch control */
- wlc_phy_antsel_init(wlc_hw->band->pi, false);
-
- } else if (wlc_hw->antsel_type == ANTSEL_2x4) {
- gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);
- /*
- * The board itself is powered by these GPIOs
- * (when not sending pattern) so set them high
- */
- OR_REG(&regs->psm_gpio_oe,
- (BOARD_GPIO_12 | BOARD_GPIO_13));
- OR_REG(&regs->psm_gpio_out,
- (BOARD_GPIO_12 | BOARD_GPIO_13));
-
- /* Enable antenna diversity, use 2x4 mode */
- brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
- MHF3_ANTSEL_EN, BRCM_BAND_ALL);
- brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,
- BRCM_BAND_ALL);
-
- /* Configure the desired clock to be 4Mhz */
- brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV,
- ANTSEL_CLKDIV_4MHZ);
- }
-
- /* gpio 9 controls the PA. ucode is responsible for wiggling out and oe */
- if (wlc_hw->boardflags & BFL_PACTRL)
- gm |= gc |= BOARD_GPIO_PACTRL;
-
- /* apply to gpiocontrol register */
- ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
-}
-
-static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
-{
- struct brcms_c_info *wlc;
- wlc = wlc_hw->wlc;
-
- if (wlc_hw->ucode_loaded)
- return;
-
- if (D11REV_IS(wlc_hw->corerev, 23)) {
- if (BRCMS_ISNPHY(wlc_hw->band)) {
- brcms_ucode_write(wlc_hw, bcm43xx_16_mimo,
- bcm43xx_16_mimosz);
- wlc_hw->ucode_loaded = true;
- } else
- wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
- "corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev);
- } else if (D11REV_IS(wlc_hw->corerev, 24)) {
- if (BRCMS_ISLCNPHY(wlc_hw->band)) {
- brcms_ucode_write(wlc_hw, bcm43xx_24_lcn,
- bcm43xx_24_lcnsz);
- wlc_hw->ucode_loaded = true;
- } else {
- wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
- "corerev %d\n",
- __func__, wlc_hw->unit, wlc_hw->corerev);
- }
- }
-}
-
-static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[],
- const uint nbytes) {
- d11regs_t *regs = wlc_hw->regs;
- uint i;
- uint count;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- count = (nbytes / sizeof(u32));
-
- W_REG(&regs->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL));
- (void)R_REG(&regs->objaddr);
- for (i = 0; i < count; i++)
- W_REG(&regs->objdata, ucode[i]);
-}
-
-static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
- const struct d11init *inits)
-{
- int i;
- volatile u8 *base;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- base = (volatile u8 *)wlc_hw->regs;
-
- for (i = 0; inits[i].addr != 0xffff; i++) {
- if (inits[i].size == 2)
- W_REG((u16 *)(base + inits[i].addr),
- inits[i].value);
- else if (inits[i].size == 4)
- W_REG((u32 *)(base + inits[i].addr),
- inits[i].value);
- }
-}
-
-static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
-{
- u16 phyctl;
- u16 phytxant = wlc_hw->bmac_phytxant;
- u16 mask = PHY_TXC_ANT_MASK;
-
- /* set the Probe Response frame phy control word */
- phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
- phyctl = (phyctl & ~mask) | phytxant;
- brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
-
- /* set the Response (ACK/CTS) frame phy control word */
- phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
- phyctl = (phyctl & ~mask) | phytxant;
- brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
-}
-
-void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)
-{
- /* update sw state */
- wlc_hw->bmac_phytxant = phytxant;
-
- /* push to ucode if up */
- if (!wlc_hw->up)
- return;
- brcms_c_ucode_txant_set(wlc_hw);
-
-}
-
-u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw)
-{
- return (u16) wlc_hw->wlc->stf->txant;
-}
-
-void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
-{
- wlc_hw->antsel_type = antsel_type;
-
- /* Update the antsel type for phy module to use */
- wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
-}
-
-void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
-{
- bool fatal = false;
- uint unit;
- uint intstatus, idx;
- d11regs_t *regs = wlc_hw->regs;
- struct wiphy *wiphy = wlc_hw->wlc->wiphy;
-
- unit = wlc_hw->unit;
-
- for (idx = 0; idx < NFIFO; idx++) {
- /* read intstatus register and ignore any non-error bits */
- intstatus =
- R_REG(&regs->intctrlregs[idx].intstatus) & I_ERRORS;
- if (!intstatus)
- continue;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n",
- unit, idx, intstatus);
-
- if (intstatus & I_RO) {
- wiphy_err(wiphy, "wl%d: fifo %d: receive fifo "
- "overflow\n", unit, idx);
- fatal = true;
- }
-
- if (intstatus & I_PC) {
- wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n",
- unit, idx);
- fatal = true;
- }
-
- if (intstatus & I_PD) {
- wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit,
- idx);
- fatal = true;
- }
-
- if (intstatus & I_DE) {
- wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol "
- "error\n", unit, idx);
- fatal = true;
- }
-
- if (intstatus & I_RU) {
- wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor "
- "underflow\n", idx, unit);
- }
-
- if (intstatus & I_XU) {
- wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo "
- "underflow\n", idx, unit);
- fatal = true;
- }
-
- if (fatal) {
- brcms_c_fatal_error(wlc_hw->wlc); /* big hammer */
- break;
- } else
- W_REG(&regs->intctrlregs[idx].intstatus,
- intstatus);
- }
-}
-
-void brcms_c_intrson(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- wlc->macintmask = wlc->defmacintmask;
- W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
-}
-
-/* callback for siutils.c, which has only wlc handler, no wl
- * they both check up, not only because there is no need to off/restore d11 interrupt
- * but also because per-port code may require sync with valid interrupt.
- */
-
-static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc)
-{
- if (!wlc->hw->up)
- return 0;
-
- return brcms_intrsoff(wlc->wl);
-}
-
-static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask)
-{
- if (!wlc->hw->up)
- return;
-
- brcms_intrsrestore(wlc->wl, macintmask);
-}
-
-u32 brcms_c_intrsoff(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- u32 macintmask;
-
- if (!wlc_hw->clk)
- return 0;
-
- macintmask = wlc->macintmask; /* isr can still happen */
-
- W_REG(&wlc_hw->regs->macintmask, 0);
- (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */
- udelay(1); /* ensure int line is no longer driven */
- wlc->macintmask = 0;
-
- /* return previous macintmask; resolve race between us and our isr */
- return wlc->macintstatus ? 0 : macintmask;
-}
-
-void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- if (!wlc_hw->clk)
- return;
-
- wlc->macintmask = macintmask;
- W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
-}
-
-static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, mbool flags)
-{
- u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
-
- if (on) {
- /* suspend tx fifos */
- brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
- brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
- brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);
- brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
-
- /* zero the address match register so we do not send ACKs */
- brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
- null_ether_addr);
- } else {
- /* resume tx fifos */
- if (!wlc_hw->wlc->tx_suspended) {
- brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
- }
- brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);
- brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);
- brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
-
- /* Restore address */
- brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
- wlc_hw->etheraddr);
- }
-
- wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
-
- if (on)
- brcms_c_ucode_mute_override_set(wlc_hw);
- else
- brcms_c_ucode_mute_override_clear(wlc_hw);
-}
-
-int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
- uint *blocks)
-{
- if (fifo >= NFIFO)
- return -EINVAL;
-
- *blocks = wlc_hw->xmtfifo_sz[fifo];
-
- return 0;
-}
-
-/* brcms_b_tx_fifo_suspended:
- * Check the MAC's tx suspend status for a tx fifo.
- *
- * When the MAC acknowledges a tx suspend, it indicates that no more
- * packets will be transmitted out the radio. This is independent of
- * DMA channel suspension---the DMA may have finished suspending, or may still
- * be pulling data into a tx fifo, by the time the MAC acks the suspend
- * request.
- */
-static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
- uint tx_fifo)
-{
- /* check that a suspend has been requested and is no longer pending */
-
- /*
- * for DMA mode, the suspend request is set in xmtcontrol of the DMA engine,
- * and the tx fifo suspend at the lower end of the MAC is acknowledged in the
- * chnstatus register.
- * The tx fifo suspend completion is independent of the DMA suspend completion and
- * may be acked before or after the DMA is suspended.
- */
- if (dma_txsuspended(wlc_hw->di[tx_fifo]) &&
- (R_REG(&wlc_hw->regs->chnstatus) &
- (1 << tx_fifo)) == 0)
- return true;
-
- return false;
-}
-
-static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
- uint tx_fifo)
-{
- u8 fifo = 1 << tx_fifo;
-
- /* Two clients of this code, 11h Quiet period and scanning. */
-
- /* only suspend if not already suspended */
- if ((wlc_hw->suspended_fifos & fifo) == fifo)
- return;
-
- /* force the core awake only if not already */
- if (wlc_hw->suspended_fifos == 0)
- brcms_c_ucode_wake_override_set(wlc_hw,
- BRCMS_WAKE_OVERRIDE_TXFIFO);
-
- wlc_hw->suspended_fifos |= fifo;
-
- if (wlc_hw->di[tx_fifo]) {
- /* Suspending AMPDU transmissions in the middle can cause underflow
- * which may result in mismatch between ucode and driver
- * so suspend the mac before suspending the FIFO
- */
- if (BRCMS_PHY_11N_CAP(wlc_hw->band))
- brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
-
- dma_txsuspend(wlc_hw->di[tx_fifo]);
-
- if (BRCMS_PHY_11N_CAP(wlc_hw->band))
- brcms_c_enable_mac(wlc_hw->wlc);
- }
-}
-
-static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
- uint tx_fifo)
-{
- /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
- * but need to be done here for PIO otherwise the watchdog will catch
- * the inconsistency and fire
- */
- /* Two clients of this code, 11h Quiet period and scanning. */
- if (wlc_hw->di[tx_fifo])
- dma_txresume(wlc_hw->di[tx_fifo]);
-
- /* allow core to sleep again */
- if (wlc_hw->suspended_fifos == 0)
- return;
- else {
- wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
- if (wlc_hw->suspended_fifos == 0)
- brcms_c_ucode_wake_override_clear(wlc_hw,
- BRCMS_WAKE_OVERRIDE_TXFIFO);
- }
-}
-
-/*
- * Read and clear macintmask and macintstatus and intstatus registers.
- * This routine should be called with interrupts off
- * Return:
- * -1 if DEVICEREMOVED(wlc) evaluates to true;
- * 0 if the interrupt is not for us, or we are in some special cases;
- * device interrupt status bits otherwise.
- */
-static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- d11regs_t *regs = wlc_hw->regs;
- u32 macintstatus;
-
- /* macintstatus includes a DMA interrupt summary bit */
- macintstatus = R_REG(&regs->macintstatus);
-
- BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit,
- macintstatus);
-
- /* detect cardbus removed, in power down(suspend) and in reset */
- if (DEVICEREMOVED(wlc))
- return -1;
-
- /* DEVICEREMOVED succeeds even when the core is still resetting,
- * handle that case here.
- */
- if (macintstatus == 0xffffffff)
- return 0;
-
- /* defer unsolicited interrupts */
- macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask);
-
- /* if not for us */
- if (macintstatus == 0)
- return 0;
-
- /* interrupts are already turned off for CFE build
- * Caution: For CFE Turning off the interrupts again has some undesired
- * consequences
- */
- /* turn off the interrupts */
- W_REG(&regs->macintmask, 0);
- (void)R_REG(&regs->macintmask); /* sync readback */
- wlc->macintmask = 0;
-
- /* clear device interrupts */
- W_REG(&regs->macintstatus, macintstatus);
-
- /* MI_DMAINT is indication of non-zero intstatus */
- if (macintstatus & MI_DMAINT) {
- /*
- * only fifo interrupt enabled is I_RI in
- * RX_FIFO. If MI_DMAINT is set, assume it
- * is set and clear the interrupt.
- */
- W_REG(&regs->intctrlregs[RX_FIFO].intstatus,
- DEF_RXINTMASK);
- }
-
- return macintstatus;
-}
-
-/* Update wlc->macintstatus and wlc->intstatus[]. */
-/* Return true if they are updated successfully. false otherwise */
-bool brcms_c_intrsupd(struct brcms_c_info *wlc)
-{
- u32 macintstatus;
-
- /* read and clear macintstatus and intstatus registers */
- macintstatus = wlc_intstatus(wlc, false);
-
- /* device is removed */
- if (macintstatus == 0xffffffff)
- return false;
-
- /* update interrupt status in software */
- wlc->macintstatus |= macintstatus;
-
- return true;
-}
-
-/*
- * First-level interrupt processing.
- * Return true if this was our interrupt, false otherwise.
- * *wantdpc will be set to true if further brcms_c_dpc() processing is required,
- * false otherwise.
- */
-bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- u32 macintstatus;
-
- *wantdpc = false;
-
- if (!wlc_hw->up || !wlc->macintmask)
- return false;
-
- /* read and clear macintstatus and intstatus registers */
- macintstatus = wlc_intstatus(wlc, true);
-
- if (macintstatus == 0xffffffff)
- wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code"
- " path\n");
-
- /* it is not for us */
- if (macintstatus == 0)
- return false;
-
- *wantdpc = true;
-
- /* save interrupt status bits */
- wlc->macintstatus = macintstatus;
-
- return true;
-
-}
-
-static bool
-brcms_b_dotxstatus(struct brcms_hardware *wlc_hw, struct tx_status *txs,
- u32 s2)
-{
- /* discard intermediate indications for ucode with one legitimate case:
- * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
- * tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
- * transmission count)
- */
- if (!(txs->status & TX_STATUS_AMPDU)
- && (txs->status & TX_STATUS_INTERMEDIATE)) {
- return false;
- }
-
- return brcms_c_dotxstatus(wlc_hw->wlc, txs, s2);
-}
-
-/* process tx completion events in BMAC
- * Return true if more tx status need to be processed. false otherwise.
- */
-static bool
-brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
-{
- bool morepending = false;
- struct brcms_c_info *wlc = wlc_hw->wlc;
- d11regs_t *regs;
- struct tx_status txstatus, *txs;
- u32 s1, s2;
- uint n = 0;
- /*
- * Param 'max_tx_num' indicates max. # tx status to process before
- * break out.
- */
- uint max_tx_num = bound ? wlc->pub->tunables->txsbnd : -1;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- txs = &txstatus;
- regs = wlc_hw->regs;
- while (!(*fatal)
- && (s1 = R_REG(&regs->frmtxstatus)) & TXS_V) {
-
- if (s1 == 0xffffffff) {
- wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
- wlc_hw->unit, __func__);
- return morepending;
- }
-
- s2 = R_REG(&regs->frmtxstatus2);
-
- txs->status = s1 & TXS_STATUS_MASK;
- txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
- txs->sequence = s2 & TXS_SEQ_MASK;
- txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
- txs->lasttxtime = 0;
-
- *fatal = brcms_b_dotxstatus(wlc_hw, txs, s2);
-
- /* !give others some time to run! */
- if (++n >= max_tx_num)
- break;
- }
-
- if (*fatal)
- return 0;
-
- if (n >= max_tx_num)
- morepending = true;
-
- if (!pktq_empty(&wlc->pkt_queue->q))
- brcms_c_send_q(wlc);
-
- return morepending;
-}
-
-void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- d11regs_t *regs = wlc_hw->regs;
- u32 mc, mi;
- struct wiphy *wiphy = wlc->wiphy;
-
- BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
- wlc_hw->band->bandunit);
-
- /*
- * Track overlapping suspend requests
- */
- wlc_hw->mac_suspend_depth++;
- if (wlc_hw->mac_suspend_depth > 1)
- return;
-
- /* force the core awake */
- brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
-
- mc = R_REG(&regs->maccontrol);
-
- if (mc == 0xffffffff) {
- wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
- __func__);
- brcms_down(wlc->wl);
- return;
- }
- WARN_ON(mc & MCTL_PSM_JMP_0);
- WARN_ON(!(mc & MCTL_PSM_RUN));
- WARN_ON(!(mc & MCTL_EN_MAC));
-
- mi = R_REG(&regs->macintstatus);
- if (mi == 0xffffffff) {
- wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
- __func__);
- brcms_down(wlc->wl);
- return;
- }
- WARN_ON(mi & MI_MACSSPNDD);
-
- brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0);
-
- SPINWAIT(!(R_REG(&regs->macintstatus) & MI_MACSSPNDD),
- BRCMS_MAX_MAC_SUSPEND);
-
- if (!(R_REG(&regs->macintstatus) & MI_MACSSPNDD)) {
- wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
- " and MI_MACSSPNDD is still not on.\n",
- wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);
- wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
- "psm_brc 0x%04x\n", wlc_hw->unit,
- R_REG(&regs->psmdebug),
- R_REG(&regs->phydebug),
- R_REG(&regs->psm_brc));
- }
-
- mc = R_REG(&regs->maccontrol);
- if (mc == 0xffffffff) {
- wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
- __func__);
- brcms_down(wlc->wl);
- return;
- }
- WARN_ON(mc & MCTL_PSM_JMP_0);
- WARN_ON(!(mc & MCTL_PSM_RUN));
- WARN_ON(mc & MCTL_EN_MAC);
-}
-
-void brcms_c_enable_mac(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- d11regs_t *regs = wlc_hw->regs;
- u32 mc, mi;
-
- BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
- wlc->band->bandunit);
-
- /*
- * Track overlapping suspend requests
- */
- wlc_hw->mac_suspend_depth--;
- if (wlc_hw->mac_suspend_depth > 0)
- return;
-
- mc = R_REG(&regs->maccontrol);
- WARN_ON(mc & MCTL_PSM_JMP_0);
- WARN_ON(mc & MCTL_EN_MAC);
- WARN_ON(!(mc & MCTL_PSM_RUN));
-
- brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);
- W_REG(&regs->macintstatus, MI_MACSSPNDD);
-
- mc = R_REG(&regs->maccontrol);
- WARN_ON(mc & MCTL_PSM_JMP_0);
- WARN_ON(!(mc & MCTL_EN_MAC));
- WARN_ON(!(mc & MCTL_PSM_RUN));
-
- mi = R_REG(&regs->macintstatus);
- WARN_ON(mi & MI_MACSSPNDD);
-
- brcms_c_ucode_wake_override_clear(wlc_hw,
- BRCMS_WAKE_OVERRIDE_MACSUSPEND);
-}
-
-static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
-{
- u8 rate;
- u8 rates[8] = {
- BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
- BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
- };
- u16 entry_ptr;
- u16 pctl1;
- uint i;
-
- if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
- return;
-
- /* walk the phy rate table and update the entries */
- for (i = 0; i < ARRAY_SIZE(rates); i++) {
- rate = rates[i];
-
- entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
-
- /* read the SHM Rate Table entry OFDM PCTL1 values */
- pctl1 =
- brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
-
- /* modify the value */
- pctl1 &= ~PHY_TXC1_MODE_MASK;
- pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
-
- /* Update the SHM Rate Table entry OFDM PCTL1 values */
- brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
- pctl1);
- }
-}
-
-static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
- u8 rate)
-{
- uint i;
- u8 plcp_rate = 0;
- struct plcp_signal_rate_lookup {
- u8 rate;
- u8 signal_rate;
- };
- /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
- const struct plcp_signal_rate_lookup rate_lookup[] = {
- {BRCM_RATE_6M, 0xB},
- {BRCM_RATE_9M, 0xF},
- {BRCM_RATE_12M, 0xA},
- {BRCM_RATE_18M, 0xE},
- {BRCM_RATE_24M, 0x9},
- {BRCM_RATE_36M, 0xD},
- {BRCM_RATE_48M, 0x8},
- {BRCM_RATE_54M, 0xC}
- };
-
- for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
- if (rate == rate_lookup[i].rate) {
- plcp_rate = rate_lookup[i].signal_rate;
- break;
- }
- }
-
- /* Find the SHM pointer to the rate table entry by looking in the
- * Direct-map Table
- */
- return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
-}
-
-void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
-{
- wlc_hw->hw_stf_ss_opmode = stf_mode;
-
- if (wlc_hw->clk)
- brcms_upd_ofdm_pctl1_table(wlc_hw);
-}
-
-void
-brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
- u32 *tsf_h_ptr)
-{
- d11regs_t *regs = wlc_hw->regs;
-
- /* read the tsf timer low, then high to get an atomic read */
- *tsf_l_ptr = R_REG(&regs->tsf_timerlow);
- *tsf_h_ptr = R_REG(&regs->tsf_timerhigh);
-
- return;
-}
-
-static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
-{
- d11regs_t *regs;
- u32 w, val;
- struct wiphy *wiphy = wlc_hw->wlc->wiphy;
-
- BCMMSG(wiphy, "wl%d\n", wlc_hw->unit);
-
- regs = wlc_hw->regs;
-
- /* Validate dchip register access */
-
- W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
- (void)R_REG(&regs->objaddr);
- w = R_REG(&regs->objdata);
-
- /* Can we write and read back a 32bit register? */
- W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
- (void)R_REG(&regs->objaddr);
- W_REG(&regs->objdata, (u32) 0xaa5555aa);
-
- W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
- (void)R_REG(&regs->objaddr);
- val = R_REG(&regs->objdata);
- if (val != (u32) 0xaa5555aa) {
- wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
- "expected 0xaa5555aa\n", wlc_hw->unit, val);
- return false;
- }
-
- W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
- (void)R_REG(&regs->objaddr);
- W_REG(&regs->objdata, (u32) 0x55aaaa55);
-
- W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
- (void)R_REG(&regs->objaddr);
- val = R_REG(&regs->objdata);
- if (val != (u32) 0x55aaaa55) {
- wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
- "expected 0x55aaaa55\n", wlc_hw->unit, val);
- return false;
- }
-
- W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
- (void)R_REG(&regs->objaddr);
- W_REG(&regs->objdata, w);
-
- /* clear CFPStart */
- W_REG(&regs->tsf_cfpstart, 0);
-
- w = R_REG(&regs->maccontrol);
- if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
- (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
- wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = "
- "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w,
- (MCTL_IHR_EN | MCTL_WAKE),
- (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
- return false;
- }
-
- return true;
-}
-
-#define PHYPLL_WAIT_US 100000
-
-void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
-{
- d11regs_t *regs;
- u32 tmp;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- tmp = 0;
- regs = wlc_hw->regs;
-
- if (on) {
- if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
- OR_REG(&regs->clk_ctl_st,
- (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL |
- CCS_ERSRC_REQ_PHYPLL));
- SPINWAIT((R_REG(&regs->clk_ctl_st) &
- (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT),
- PHYPLL_WAIT_US);
-
- tmp = R_REG(&regs->clk_ctl_st);
- if ((tmp & (CCS_ERSRC_AVAIL_HT)) !=
- (CCS_ERSRC_AVAIL_HT)) {
- wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY"
- " PLL failed\n", __func__);
- }
- } else {
- OR_REG(&regs->clk_ctl_st,
- (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL));
- SPINWAIT((R_REG(&regs->clk_ctl_st) &
- (CCS_ERSRC_AVAIL_D11PLL |
- CCS_ERSRC_AVAIL_PHYPLL)) !=
- (CCS_ERSRC_AVAIL_D11PLL |
- CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);
-
- tmp = R_REG(&regs->clk_ctl_st);
- if ((tmp &
- (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
- !=
- (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) {
- wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on "
- "PHY PLL failed\n", __func__);
- }
- }
- } else {
- /* Since the PLL may be shared, other cores can still be requesting it;
- * so we'll deassert the request but not wait for status to comply.
- */
- AND_REG(&regs->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL);
- tmp = R_REG(&regs->clk_ctl_st);
- }
-}
-
-void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
-{
- bool dev_gone;
-
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
- dev_gone = DEVICEREMOVED(wlc_hw->wlc);
-
- if (dev_gone)
- return;
-
- if (wlc_hw->noreset)
- return;
-
- /* radio off */
- wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
-
- /* turn off analog core */
- wlc_phy_anacore(wlc_hw->band->pi, OFF);
-
- /* turn off PHYPLL to save power */
- brcms_b_core_phypll_ctl(wlc_hw, false);
-
- /* No need to set wlc->pub->radio_active = OFF
- * because this function needs down capability and
- * radio_active is designed for BCMNODOWN.
- */
-
- /* remove gpio controls */
- if (wlc_hw->ucode_dbgsel)
- ai_gpiocontrol(wlc_hw->sih, ~0, 0, GPIO_DRV_PRIORITY);
-
- wlc_hw->clk = false;
- ai_core_disable(wlc_hw->sih, 0);
- wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
-}
-
-/* power both the pll and external oscillator on/off */
-static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
-
- /* dont power down if plldown is false or we must poll hw radio disable */
- if (!want && wlc_hw->pllreq)
- return;
-
- if (wlc_hw->sih)
- ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
-
- wlc_hw->sbclk = want;
- if (!wlc_hw->sbclk) {
- wlc_hw->clk = false;
- if (wlc_hw->band && wlc_hw->band->pi)
- wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
- }
-}
-
-static void brcms_c_flushqueues(struct brcms_c_info *wlc)
-{
- struct brcms_hardware *wlc_hw = wlc->hw;
- uint i;
-
- wlc->txpend16165war = 0;
-
- /* free any posted tx packets */
- for (i = 0; i < NFIFO; i++)
- if (wlc_hw->di[i]) {
- dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
- TXPKTPENDCLR(wlc, i);
- BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i);
- }
-
- /* free any posted rx packets */
- dma_rxreclaim(wlc_hw->di[RX_FIFO]);
-}
-
-u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
-{
- return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
-}
-
-void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
-{
- brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
-}
-
-static u16
-brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
-{
- d11regs_t *regs = wlc_hw->regs;
- volatile u16 *objdata_lo = (volatile u16 *)&regs->objdata;
- volatile u16 *objdata_hi = objdata_lo + 1;
- u16 v;
-
- W_REG(&regs->objaddr, sel | (offset >> 2));
- (void)R_REG(&regs->objaddr);
- if (offset & 2) {
- v = R_REG(objdata_hi);
- } else {
- v = R_REG(objdata_lo);
- }
-
- return v;
-}
-
-static void
-brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,
- u32 sel)
-{
- d11regs_t *regs = wlc_hw->regs;
- volatile u16 *objdata_lo = (volatile u16 *)&regs->objdata;
- volatile u16 *objdata_hi = objdata_lo + 1;
-
- W_REG(&regs->objaddr, sel | (offset >> 2));
- (void)R_REG(&regs->objaddr);
- if (offset & 2) {
- W_REG(objdata_hi, v);
- } else {
- W_REG(objdata_lo, v);
- }
-}
-
-/* Copy a buffer to shared memory of specified type .
- * SHM 'offset' needs to be an even address and
- * Buffer length 'len' must be an even number of bytes
- * 'sel' selects the type of memory
- */
-void
-brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset,
- const void *buf, int len, u32 sel)
-{
- u16 v;
- const u8 *p = (const u8 *)buf;
- int i;
-
- if (len <= 0 || (offset & 1) || (len & 1))
- return;
-
- for (i = 0; i < len; i += 2) {
- v = p[i] | (p[i + 1] << 8);
- brcms_b_write_objmem(wlc_hw, offset + i, v, sel);
- }
-}
-
-/* Copy a piece of shared memory of specified type to a buffer .
- * SHM 'offset' needs to be an even address and
- * Buffer length 'len' must be an even number of bytes
- * 'sel' selects the type of memory
- */
-void
-brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,
- int len, u32 sel)
-{
- u16 v;
- u8 *p = (u8 *) buf;
- int i;
-
- if (len <= 0 || (offset & 1) || (len & 1))
- return;
-
- for (i = 0; i < len; i += 2) {
- v = brcms_b_read_objmem(wlc_hw, offset + i, sel);
- p[i] = v & 0xFF;
- p[i + 1] = (v >> 8) & 0xFF;
- }
-}
-
-void brcms_b_copyfrom_vars(struct brcms_hardware *wlc_hw, char **buf,
- uint *len)
-{
- BCMMSG(wlc_hw->wlc->wiphy, "nvram vars totlen=%d\n",
- wlc_hw->vars_size);
-
- *buf = wlc_hw->vars;
- *len = wlc_hw->vars_size;
-}
-
-void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, u16 SRL, u16 LRL)
-{
- wlc_hw->SRL = SRL;
- wlc_hw->LRL = LRL;
-
- /* write retry limit to SCR, shouldn't need to suspend */
- if (wlc_hw->up) {
- W_REG(&wlc_hw->regs->objaddr,
- OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
- (void)R_REG(&wlc_hw->regs->objaddr);
- W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL);
- W_REG(&wlc_hw->regs->objaddr,
- OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
- (void)R_REG(&wlc_hw->regs->objaddr);
- W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL);
- }
-}
-
-void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, mbool req_bit)
-{
- if (set) {
- if (mboolisset(wlc_hw->pllreq, req_bit))
- return;
-
- mboolset(wlc_hw->pllreq, req_bit);
-
- if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
- if (!wlc_hw->sbclk) {
- brcms_b_xtal(wlc_hw, ON);
- }
- }
- } else {
- if (!mboolisset(wlc_hw->pllreq, req_bit))
- return;
-
- mboolclr(wlc_hw->pllreq, req_bit);
-
- if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
- if (wlc_hw->sbclk) {
- brcms_b_xtal(wlc_hw, OFF);
- }
- }
- }
-
- return;
-}
-
-u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
-{
- u16 table_ptr;
- u8 phy_rate, index;
-
- /* get the phy specific rate encoding for the PLCP SIGNAL field */
- if (IS_OFDM(rate))
- table_ptr = M_RT_DIRMAP_A;
- else
- table_ptr = M_RT_DIRMAP_B;
-
- /* for a given rate, the LS-nibble of the PLCP SIGNAL field is
- * the index into the rate table.
- */
- phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
- index = phy_rate & 0xf;
-
- /* Find the SHM pointer to the rate table entry by looking in the
- * Direct-map Table
- */
- return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
-}
-
-void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
-{
- wlc_hw->antsel_avail = antsel_avail;
-}
diff --git a/drivers/staging/brcm80211/brcmsmac/bmac.h b/drivers/staging/brcm80211/brcmsmac/bmac.h
deleted file mode 100644
index 3c9ad4f3bd22..000000000000
--- a/drivers/staging/brcm80211/brcmsmac/bmac.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef _BRCM_BOTTOM_MAC_H_
-#define _BRCM_BOTTOM_MAC_H_
-
-#include <brcmu_wifi.h>
-#include "types.h"
-
-/* dup state between BMAC(struct brcms_hardware) and HIGH(struct brcms_c_info)
- driver */
-struct brcms_b_state {
- u32 machwcap; /* mac hw capibility */
- u32 preamble_ovr; /* preamble override */
-};
-
-enum {
- IOV_BMAC_DIAG,
- IOV_BMAC_SBGPIOTIMERVAL,
- IOV_BMAC_SBGPIOOUT,
- IOV_BMAC_CCGPIOCTRL, /* CC GPIOCTRL REG */
- IOV_BMAC_CCGPIOOUT, /* CC GPIOOUT REG */
- IOV_BMAC_CCGPIOOUTEN, /* CC GPIOOUTEN REG */
- IOV_BMAC_CCGPIOIN, /* CC GPIOIN REG */
- IOV_BMAC_WPSGPIO, /* WPS push button GPIO pin */
- IOV_BMAC_OTPDUMP,
- IOV_BMAC_OTPSTAT,
- IOV_BMAC_PCIEASPM, /* obfuscation clkreq/aspm control */
- IOV_BMAC_PCIEADVCORRMASK, /* advanced correctable error mask */
- IOV_BMAC_PCIECLKREQ, /* PCIE 1.1 clockreq enab support */
- IOV_BMAC_PCIELCREG, /* PCIE LCREG */
- IOV_BMAC_SBGPIOTIMERMASK,
- IOV_BMAC_RFDISABLEDLY,
- IOV_BMAC_PCIEREG, /* PCIE REG */
- IOV_BMAC_PCICFGREG, /* PCI Config register */
- IOV_BMAC_PCIESERDESREG, /* PCIE SERDES REG (dev, 0}offset) */
- IOV_BMAC_PCIEGPIOOUT, /* PCIEOUT REG */
- IOV_BMAC_PCIEGPIOOUTEN, /* PCIEOUTEN REG */
- IOV_BMAC_PCIECLKREQENCTRL, /* clkreqenctrl REG (PCIE REV > 6.0 */
- IOV_BMAC_DMALPBK,
- IOV_BMAC_CCREG,
- IOV_BMAC_COREREG,
- IOV_BMAC_SDCIS,
- IOV_BMAC_SDIO_DRIVE,
- IOV_BMAC_OTPW,
- IOV_BMAC_NVOTPW,
- IOV_BMAC_SROM,
- IOV_BMAC_SRCRC,
- IOV_BMAC_CIS_SOURCE,
- IOV_BMAC_CISVAR,
- IOV_BMAC_OTPLOCK,
- IOV_BMAC_OTP_CHIPID,
- IOV_BMAC_CUSTOMVAR1,
- IOV_BMAC_BOARDFLAGS,
- IOV_BMAC_BOARDFLAGS2,
- IOV_BMAC_WPSLED,
- IOV_BMAC_NVRAM_SOURCE,
- IOV_BMAC_OTP_RAW_READ,
- IOV_BMAC_LAST
-};
-
-extern int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device,
- uint unit, bool piomode, void *regsva, uint bustype,
- void *btparam);
-extern int brcms_b_detach(struct brcms_c_info *wlc);
-extern void brcms_b_watchdog(void *arg);
-
-/* up/down, reset, clk */
-extern void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw,
- uint offset, const void *buf, int len,
- u32 sel);
-extern void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset,
- void *buf, int len, u32 sel);
-#define brcms_b_copyfrom_shm(wlc_hw, offset, buf, len) \
- brcms_b_copyfrom_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL)
-#define brcms_b_copyto_shm(wlc_hw, offset, buf, len) \
- brcms_b_copyto_objmem(wlc_hw, offset, buf, len, OBJADDR_SHM_SEL)
-
-extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw);
-extern void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on);
-extern void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk);
-extern void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk);
-extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw);
-extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags);
-extern void brcms_b_reset(struct brcms_hardware *wlc_hw);
-extern void brcms_b_init(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
- bool mute);
-extern int brcms_b_up_prep(struct brcms_hardware *wlc_hw);
-extern int brcms_b_up_finish(struct brcms_hardware *wlc_hw);
-extern int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw);
-extern int brcms_b_down_finish(struct brcms_hardware *wlc_hw);
-extern void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode);
-
-/* chanspec, ucode interface */
-extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw,
- chanspec_t chanspec,
- bool mute, struct txpwr_limits *txpwr);
-
-extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
- uint *blocks);
-extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask,
- u16 val, int bands);
-extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val);
-extern u16 brcms_b_mhf_get(struct brcms_hardware *wlc_hw, u8 idx, int bands);
-extern void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant);
-extern u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw);
-extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw,
- u8 antsel_type);
-extern int brcms_b_state_get(struct brcms_hardware *wlc_hw,
- struct brcms_b_state *state);
-extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset,
- u16 v);
-extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset);
-extern void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw,
- int offset, int len, void *buf);
-extern void brcms_b_copyfrom_vars(struct brcms_hardware *wlc_hw, char **buf,
- uint *len);
-
-extern void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw,
- u8 *ea);
-
-extern bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw);
-extern void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw,
- bool shortslot);
-extern void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw,
- u8 stf_mode);
-
-extern void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw);
-
-extern void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
- u32 override_bit);
-extern void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
- u32 override_bit);
-
-extern void brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw,
- int match_reg_offset,
- const u8 *addr);
-extern void brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw,
- void *bcn, int len, bool both);
-
-extern void brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
- u32 *tsf_h_ptr);
-extern void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin);
-extern void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax);
-
-extern void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, u16 SRL,
- u16 LRL);
-
-extern void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw);
-
-
-/* API for BMAC driver (e.g. wlc_phy.c etc) */
-
-extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw);
-extern void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set,
- mbool req_bit);
-extern void brcms_b_hw_up(struct brcms_hardware *wlc_hw);
-extern u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate);
-extern void brcms_b_antsel_set(struct brcms_hardware *wlc_hw,
- u32 antsel_avail);
-
-#endif /* _BRCM_BOTTOM_MAC_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/alloc.h b/drivers/staging/brcm80211/brcmsmac/brcms_trace_events.c
index f465d3043030..52fc9eeb5fa5 100644
--- a/drivers/staging/brcm80211/brcmsmac/alloc.h
+++ b/drivers/staging/brcm80211/brcmsmac/brcms_trace_events.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Broadcom Corporation
+ * Copyright (c) 2011 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,10 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-extern struct brcms_c_info *brcms_c_attach_malloc(uint unit, uint *err,
- uint devid);
-extern void brcms_c_detach_mfree(struct brcms_c_info *wlc);
+#include <linux/module.h> /* bug in tracepoint.h, it should include this */
+
+#ifndef __CHECKER__
+#include "mac80211_if.h"
+#define CREATE_TRACE_POINTS
+#include "brcms_trace_events.h"
+#endif
diff --git a/drivers/staging/brcm80211/brcmsmac/brcms_trace_events.h b/drivers/staging/brcm80211/brcmsmac/brcms_trace_events.h
new file mode 100644
index 000000000000..27dd73eef56d
--- /dev/null
+++ b/drivers/staging/brcm80211/brcmsmac/brcms_trace_events.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM brcmsmac
+
+#if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ)
+
+#define __TRACE_BRCMSMAC_H
+
+#include <linux/tracepoint.h>
+#include "mac80211_if.h"
+
+#ifndef CONFIG_BRCMDBG
+#undef TRACE_EVENT
+#define TRACE_EVENT(name, proto, ...) \
+static inline void trace_ ## name(proto) {}
+#endif
+
+/*
+ * We define a tracepoint, its arguments, its printk format and its
+ * 'fast binary record' layout.
+ */
+TRACE_EVENT(brcms_timer,
+ /* TPPROTO is the prototype of the function called by this tracepoint */
+ TP_PROTO(struct brcms_timer *t),
+ /*
+ * TPARGS(firstarg, p) are the parameters names, same as found in the
+ * prototype.
+ */
+ TP_ARGS(t),
+ /*
+ * Fast binary tracing: define the trace record via TP_STRUCT__entry().
+ * You can think about it like a regular C structure local variable
+ * definition.
+ */
+ TP_STRUCT__entry(
+ __field(uint, ms)
+ __field(uint, set)
+ __field(uint, periodic)
+ ),
+ TP_fast_assign(
+ __entry->ms = t->ms;
+ __entry->set = t->set;
+ __entry->periodic = t->periodic;
+ ),
+ TP_printk(
+ "ms=%u set=%u periodic=%u",
+ __entry->ms, __entry->set, __entry->periodic
+ )
+);
+
+TRACE_EVENT(brcms_dpc,
+ TP_PROTO(unsigned long data),
+ TP_ARGS(data),
+ TP_STRUCT__entry(
+ __field(unsigned long, data)
+ ),
+ TP_fast_assign(
+ __entry->data = data;
+ ),
+ TP_printk(
+ "data=%p",
+ (void *)__entry->data
+ )
+);
+
+#endif /* __TRACE_BRCMSMAC_H */
+
+#ifdef CONFIG_BRCMDBG
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE brcms_trace_events
+
+#include <trace/define_trace.h>
+
+#endif /* CONFIG_BRCMDBG */
diff --git a/drivers/staging/brcm80211/brcmsmac/channel.c b/drivers/staging/brcm80211/brcmsmac/channel.c
index f59693e1d8a2..89ad1b7dab8f 100644
--- a/drivers/staging/brcm80211/brcmsmac/channel.c
+++ b/drivers/staging/brcm80211/brcmsmac/channel.c
@@ -20,24 +20,138 @@
#include <defs.h>
#include "pub.h"
#include "phy/phy_hal.h"
-#include "bmac.h"
#include "main.h"
#include "stf.h"
#include "channel.h"
-#define VALID_CHANNEL20_DB(wlc, val) brcms_c_valid_channel20_db((wlc)->cmi, val)
-#define VALID_CHANNEL20_IN_BAND(wlc, bandunit, val) \
- brcms_c_valid_channel20_in_band((wlc)->cmi, bandunit, val)
-#define VALID_CHANNEL20(wlc, val) brcms_c_valid_channel20((wlc)->cmi, val)
+/* QDB() macro takes a dB value and converts to a quarter dB value */
+#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
+
+#define LOCALE_CHAN_01_11 (1<<0)
+#define LOCALE_CHAN_12_13 (1<<1)
+#define LOCALE_CHAN_14 (1<<2)
+#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
+#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
+#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
+#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
+#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
+#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
+#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
+#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
+#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
+#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
+#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
+#define LOCALE_CHAN_52_140_ALL (1<<14)
+#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
+
+#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \
+ LOCALE_SET_5G_LOW2 | \
+ LOCALE_SET_5G_LOW3)
+#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
+#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
+#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \
+ LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
+#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
+#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
+
+#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \
+ LOCALE_CHAN_12_13 | \
+ LOCALE_CHAN_14)
+
+#define LOCALE_RADAR_SET_NONE 0
+#define LOCALE_RADAR_SET_1 1
+
+#define LOCALE_RESTRICTED_NONE 0
+#define LOCALE_RESTRICTED_SET_2G_SHORT 1
+#define LOCALE_RESTRICTED_CHAN_165 2
+#define LOCALE_CHAN_ALL_5G 3
+#define LOCALE_RESTRICTED_JAPAN_LEGACY 4
+#define LOCALE_RESTRICTED_11D_2G 5
+#define LOCALE_RESTRICTED_11D_5G 6
+#define LOCALE_RESTRICTED_LOW_HI 7
+#define LOCALE_RESTRICTED_12_13_14 8
+
+#define LOCALE_2G_IDX_i 0
+#define LOCALE_5G_IDX_11 0
+#define LOCALE_MIMO_IDX_bn 0
+#define LOCALE_MIMO_IDX_11n 0
+
+/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
+#define BRCMS_MAXPWR_TBL_SIZE 6
+/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
+#define BRCMS_MAXPWR_MIMO_TBL_SIZE 14
+
+/* power level in group of 2.4GHz band channels:
+ * maxpwr[0] - CCK channels [1]
+ * maxpwr[1] - CCK channels [2-10]
+ * maxpwr[2] - CCK channels [11-14]
+ * maxpwr[3] - OFDM channels [1]
+ * maxpwr[4] - OFDM channels [2-10]
+ * maxpwr[5] - OFDM channels [11-14]
+ */
+
+/* maxpwr mapping to 5GHz band channels:
+ * maxpwr[0] - channels [34-48]
+ * maxpwr[1] - channels [52-60]
+ * maxpwr[2] - channels [62-64]
+ * maxpwr[3] - channels [100-140]
+ * maxpwr[4] - channels [149-165]
+ */
+#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */
+
+#define LC(id) LOCALE_MIMO_IDX_ ## id
+
+#define LC_2G(id) LOCALE_2G_IDX_ ## id
+
+#define LC_5G(id) LOCALE_5G_IDX_ ## id
+
+#define LOCALES(band2, band5, mimo2, mimo5) \
+ {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
+
+/* macro to get 2.4 GHz channel group index for tx power */
+#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2))
+#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5))
+
+/* macro to get 5 GHz channel group index for tx power */
+#define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \
+ (((c) < 62) ? 1 : \
+ (((c) < 100) ? 2 : \
+ (((c) < 149) ? 3 : 4))))
+
+#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
struct brcms_cm_band {
- u8 locale_flags; /* struct locale_info flags */
- chanvec_t valid_channels; /* List of valid channels in the country */
- const chanvec_t *restricted_channels; /* List of restricted use channels */
- const chanvec_t *radar_channels; /* List of radar sensitive channels */
+ /* struct locale_info flags */
+ u8 locale_flags;
+ /* List of valid channels in the country */
+ struct brcms_chanvec valid_channels;
+ /* List of restricted use channels */
+ const struct brcms_chanvec *restricted_channels;
+ /* List of radar sensitive channels */
+ const struct brcms_chanvec *radar_channels;
u8 PAD[8];
};
+ /* locale per-channel tx power limits for MIMO frames
+ * maxpwr arrays are index by channel for 2.4 GHz limits, and
+ * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
+ */
+struct locale_mimo_info {
+ /* tx 20 MHz power limits, qdBm units */
+ s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
+ /* tx 40 MHz power limits, qdBm units */
+ s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
+ u8 flags;
+};
+
+/* Country names and abbreviations with locale defined from ISO 3166 */
+struct country_info {
+ const u8 locale_2G; /* 2.4G band locale */
+ const u8 locale_5G; /* 5G band locale */
+ const u8 locale_mimo_2G; /* 2.4G mimo info */
+ const u8 locale_mimo_5G; /* 5G mimo info */
+};
+
struct brcms_cm_info {
struct brcms_pub *pub;
struct brcms_c_info *wlc;
@@ -50,63 +164,23 @@ struct brcms_cm_info {
/* per-band state (one per phy/radio) */
struct brcms_cm_band bandstate[MAXBANDS];
/* quiet channels currently for radar sensitivity or 11h support */
- chanvec_t quiet_channels; /* channels on which we cannot transmit */
+ /* channels on which we cannot transmit */
+ struct brcms_chanvec quiet_channels;
};
-static int brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
- const struct country_info *country);
-static void brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, uint regrev,
- const struct country_info *country);
-static int brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm,
- const char *ccode);
-static int brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, int regrev);
-static int brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm,
- const char *ccode,
- char *mapped_ccode, uint *mapped_regrev);
-
-static const struct country_info *
-brcms_c_country_lookup_direct(const char *ccode, uint regrev);
-
-static const struct country_info *
-brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm,
- const char *ccode, char *mapped_ccode,
- uint *mapped_regrev);
-
-static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm);
-static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm);
-static bool brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm,
- chanspec_t chspec);
-static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val);
-static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
- uint bandunit, uint val);
-static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val);
-
-static const struct country_info *
-brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode);
-
-static void brcms_c_locale_get_channels(const struct locale_info *locale,
- chanvec_t *valid_channels);
-static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx);
-static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx);
-static bool brcms_c_japan(struct brcms_c_info *wlc);
-static bool brcms_c_japan_ccode(const char *ccode);
-static void brcms_c_channel_min_txpower_limits_with_local_constraint(
- struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr,
- u8 local_constraint_qdbm);
-static void brcms_c_locale_add_channels(chanvec_t *target,
- const chanvec_t *channels);
-static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx);
-static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx);
-
-/* QDB() macro takes a dB value and converts to a quarter dB value */
-#ifdef QDB
-#undef QDB
-#endif
-#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
+/* locale channel and power info. */
+struct locale_info {
+ u32 valid_channels;
+ /* List of radar sensitive channels */
+ u8 radar_channels;
+ /* List of channels used only if APs are detected */
+ u8 restricted_channels;
+ /* Max tx pwr in qdBm for each sub-band */
+ s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
+ /* Country IE advertised max tx pwr in dBm per sub-band */
+ s8 pub_maxpwr[BAND_5G_PWR_LVLS];
+ u8 flags;
+};
/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */
@@ -115,7 +189,7 @@ static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx);
*/
/* No channels */
-static const chanvec_t chanvec_none = {
+static const struct brcms_chanvec chanvec_none = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -123,7 +197,7 @@ static const chanvec_t chanvec_none = {
};
/* All 2.4 GHz HW channels */
-const chanvec_t chanvec_all_2G = {
+static const struct brcms_chanvec chanvec_all_2G = {
{0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -131,7 +205,7 @@ const chanvec_t chanvec_all_2G = {
};
/* All 5 GHz HW channels */
-const chanvec_t chanvec_all_5G = {
+static const struct brcms_chanvec chanvec_all_5G = {
{0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11,
0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11,
0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11,
@@ -142,13 +216,11 @@ const chanvec_t chanvec_all_5G = {
* Radar channel sets
*/
-/* No radar */
-#define radar_set_none chanvec_none
-
-static const chanvec_t radar_set1 = { /* Channels 52 - 64, 100 - 140 */
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */
- 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */
- 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */
+/* Channels 52 - 64, 100 - 140 */
+static const struct brcms_chanvec radar_set1 = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */
+ 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */
+ 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */
0x00, 0x00, 0x00, 0x00}
};
@@ -156,10 +228,8 @@ static const chanvec_t radar_set1 = { /* Channels 52 - 64, 100 - 140 */
* Restricted channel sets
*/
-#define restricted_set_none chanvec_none
-
/* Channels 34, 38, 42, 46 */
-static const chanvec_t restricted_set_japan_legacy = {
+static const struct brcms_chanvec restricted_set_japan_legacy = {
{0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -167,7 +237,7 @@ static const chanvec_t restricted_set_japan_legacy = {
};
/* Channels 12, 13 */
-static const chanvec_t restricted_set_2g_short = {
+static const struct brcms_chanvec restricted_set_2g_short = {
{0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -175,7 +245,7 @@ static const chanvec_t restricted_set_2g_short = {
};
/* Channel 165 */
-static const chanvec_t restricted_chan_165 = {
+static const struct brcms_chanvec restricted_chan_165 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
@@ -183,7 +253,7 @@ static const chanvec_t restricted_chan_165 = {
};
/* Channels 36 - 48 & 149 - 165 */
-static const chanvec_t restricted_low_hi = {
+static const struct brcms_chanvec restricted_low_hi = {
{0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00,
@@ -191,61 +261,21 @@ static const chanvec_t restricted_low_hi = {
};
/* Channels 12 - 14 */
-static const chanvec_t restricted_set_12_13_14 = {
+static const struct brcms_chanvec restricted_set_12_13_14 = {
{0x00, 0x70, 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}
};
-#define LOCALE_CHAN_01_11 (1<<0)
-#define LOCALE_CHAN_12_13 (1<<1)
-#define LOCALE_CHAN_14 (1<<2)
-#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */
-#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */
-#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */
-#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */
-#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */
-#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */
-#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */
-#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */
-#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */
-#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */
-#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */
-#define LOCALE_CHAN_52_140_ALL (1<<14)
-#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */
-
-#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
-#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3)
-#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2)
-#define LOCALE_CHAN_100_140 \
- (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1)
-#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3)
-#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4
-
-#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13 | LOCALE_CHAN_14)
-
-#define LOCALE_RADAR_SET_NONE 0
-#define LOCALE_RADAR_SET_1 1
-
-#define LOCALE_RESTRICTED_NONE 0
-#define LOCALE_RESTRICTED_SET_2G_SHORT 1
-#define LOCALE_RESTRICTED_CHAN_165 2
-#define LOCALE_CHAN_ALL_5G 3
-#define LOCALE_RESTRICTED_JAPAN_LEGACY 4
-#define LOCALE_RESTRICTED_11D_2G 5
-#define LOCALE_RESTRICTED_11D_5G 6
-#define LOCALE_RESTRICTED_LOW_HI 7
-#define LOCALE_RESTRICTED_12_13_14 8
-
/* global memory to provide working buffer for expanded locale */
-static const chanvec_t *g_table_radar_set[] = {
+static const struct brcms_chanvec *g_table_radar_set[] = {
&chanvec_none,
&radar_set1
};
-static const chanvec_t *g_table_restricted_chan[] = {
+static const struct brcms_chanvec *g_table_restricted_chan[] = {
&chanvec_none, /* restricted_set_none */
&restricted_set_2g_short,
&restricted_chan_165,
@@ -257,119 +287,119 @@ static const chanvec_t *g_table_restricted_chan[] = {
&restricted_set_12_13_14
};
-static const chanvec_t locale_2g_01_11 = {
+static const struct brcms_chanvec locale_2g_01_11 = {
{0xfe, 0x0f, 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}
};
-static const chanvec_t locale_2g_12_13 = {
+static const struct brcms_chanvec locale_2g_12_13 = {
{0x00, 0x30, 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}
};
-static const chanvec_t locale_2g_14 = {
+static const struct brcms_chanvec locale_2g_14 = {
{0x00, 0x40, 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}
};
-static const chanvec_t locale_5g_LOW_JP1 = {
+static const struct brcms_chanvec locale_5g_LOW_JP1 = {
{0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_LOW_JP2 = {
+static const struct brcms_chanvec locale_5g_LOW_JP2 = {
{0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_LOW1 = {
+static const struct brcms_chanvec locale_5g_LOW1 = {
{0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_LOW2 = {
+static const struct brcms_chanvec locale_5g_LOW2 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_LOW3 = {
+static const struct brcms_chanvec locale_5g_LOW3 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_MID1 = {
+static const struct brcms_chanvec locale_5g_MID1 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_MID2 = {
+static const struct brcms_chanvec locale_5g_MID2 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_MID3 = {
+static const struct brcms_chanvec locale_5g_MID3 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_HIGH1 = {
+static const struct brcms_chanvec locale_5g_HIGH1 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_HIGH2 = {
+static const struct brcms_chanvec locale_5g_HIGH2 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_HIGH3 = {
+static const struct brcms_chanvec locale_5g_HIGH3 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_52_140_ALL = {
+static const struct brcms_chanvec locale_5g_52_140_ALL = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
-static const chanvec_t locale_5g_HIGH4 = {
+static const struct brcms_chanvec locale_5g_HIGH4 = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
0x11, 0x11, 0x11, 0x11}
};
-static const chanvec_t *g_table_locale_base[] = {
+static const struct brcms_chanvec *g_table_locale_base[] = {
&locale_2g_01_11,
&locale_2g_12_13,
&locale_2g_14,
@@ -388,27 +418,25 @@ static const chanvec_t *g_table_locale_base[] = {
&locale_5g_HIGH4
};
-static void brcms_c_locale_add_channels(chanvec_t *target,
- const chanvec_t *channels)
+static void brcms_c_locale_add_channels(struct brcms_chanvec *target,
+ const struct brcms_chanvec *channels)
{
u8 i;
- for (i = 0; i < sizeof(chanvec_t); i++) {
+ for (i = 0; i < sizeof(struct brcms_chanvec); i++)
target->vec[i] |= channels->vec[i];
- }
}
static void brcms_c_locale_get_channels(const struct locale_info *locale,
- chanvec_t *channels)
+ struct brcms_chanvec *channels)
{
u8 i;
- memset(channels, 0, sizeof(chanvec_t));
+ memset(channels, 0, sizeof(struct brcms_chanvec));
for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) {
- if (locale->valid_channels & (1 << i)) {
+ if (locale->valid_channels & (1 << i))
brcms_c_locale_add_channels(channels,
g_table_locale_base[i]);
- }
}
}
@@ -438,12 +466,10 @@ static const struct locale_info locale_11 = {
BRCMS_EIRP | BRCMS_DFS_EU
};
-#define LOCALE_2G_IDX_i 0
static const struct locale_info *g_locale_2g_table[] = {
&locale_i
};
-#define LOCALE_5G_IDX_11 0
static const struct locale_info *g_locale_5g_table[] = {
&locale_11
};
@@ -461,9 +487,6 @@ static const struct locale_mimo_info locale_bn = {
0
};
-/* locale mimo 2g indexes */
-#define LOCALE_MIMO_IDX_bn 0
-
static const struct locale_mimo_info *g_mimo_2g_table[] = {
&locale_bn
};
@@ -477,28 +500,10 @@ static const struct locale_mimo_info locale_11n = {
0
};
-#define LOCALE_MIMO_IDX_11n 0
static const struct locale_mimo_info *g_mimo_5g_table[] = {
&locale_11n
};
-#ifdef LC
-#undef LC
-#endif
-#define LC(id) LOCALE_MIMO_IDX_ ## id
-
-#ifdef LC_2G
-#undef LC_2G
-#endif
-#define LC_2G(id) LOCALE_2G_IDX_ ## id
-
-#ifdef LC_5G
-#undef LC_5G
-#endif
-#define LC_5G(id) LOCALE_5G_IDX_ ## id
-
-#define LOCALES(band2, band5, mimo2, mimo5) {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)}
-
static const struct {
char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */
struct country_info country;
@@ -586,201 +591,68 @@ struct chan20_info chan20_info[] = {
static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx)
{
- if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) {
+ if (locale_idx >= ARRAY_SIZE(g_locale_2g_table))
return NULL; /* error condition */
- }
+
return g_locale_2g_table[locale_idx];
}
static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx)
{
- if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) {
+ if (locale_idx >= ARRAY_SIZE(g_locale_5g_table))
return NULL; /* error condition */
- }
+
return g_locale_5g_table[locale_idx];
}
static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx)
{
- if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) {
+ if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table))
return NULL;
- }
+
return g_mimo_2g_table[locale_idx];
}
static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx)
{
- if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) {
- return NULL;
- }
- return g_mimo_5g_table[locale_idx];
-}
-
-struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
-{
- struct brcms_cm_info *wlc_cm;
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- const struct country_info *country;
- struct brcms_pub *pub = wlc->pub;
- char *ccode;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
- wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
- if (wlc_cm == NULL) {
- wiphy_err(wlc->wiphy, "wl%d: %s: out of memory", pub->unit,
- __func__);
+ if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table))
return NULL;
- }
- wlc_cm->pub = pub;
- wlc_cm->wlc = wlc;
- wlc->cmi = wlc_cm;
-
- /* store the country code for passing up as a regulatory hint */
- ccode = getvar(wlc->pub->vars, "ccode");
- if (ccode) {
- strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
- }
-
- /* internal country information which must match regulatory constraints in firmware */
- memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
- country = brcms_c_country_lookup(wlc, country_abbrev);
-
- /* save default country for exiting 11d regulatory mode */
- strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
-
- /* initialize autocountry_default to driver default */
- strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
-
- brcms_c_set_countrycode(wlc_cm, country_abbrev);
-
- return wlc_cm;
-}
-
-void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
-{
- kfree(wlc_cm);
-}
-u8
-brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
- uint bandunit)
-{
- return wlc_cm->bandstate[bandunit].locale_flags;
-}
-
-/* set the driver's current country and regulatory information using a country code
- * as the source. Lookup built in country information found with the country code.
- */
-static int
-brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
-{
- char country_abbrev[BRCM_CNTRY_BUF_SZ];
- strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
- return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
+ return g_mimo_5g_table[locale_idx];
}
static int
-brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, int regrev)
+brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
+ char *mapped_ccode, uint *mapped_regrev)
{
- const struct country_info *country;
- char mapped_ccode[BRCM_CNTRY_BUF_SZ];
- uint mapped_regrev;
-
- /* if regrev is -1, lookup the mapped country code,
- * otherwise use the ccode and regrev directly
- */
- if (regrev == -1) {
- /* map the country code to a built-in country code, regrev, and country_info */
- country =
- brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
- &mapped_regrev);
- } else {
- /* find the matching built-in country definition */
- country = brcms_c_country_lookup_direct(ccode, regrev);
- strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
- mapped_regrev = regrev;
- }
-
- if (country == NULL)
- return -EINVAL;
-
- /* set the driver state for the country */
- brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
- mapped_regrev, country);
-
- return 0;
+ return false;
}
-/* set the driver's current country and regulatory information using a country code
- * as the source. Look up built in country information found with the country code.
+/* Lookup a country info structure from a null terminated country
+ * abbreviation and regrev directly with no translation.
*/
-static void
-brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
- const char *country_abbrev,
- const char *ccode, uint regrev,
- const struct country_info *country)
+static const struct country_info *
+brcms_c_country_lookup_direct(const char *ccode, uint regrev)
{
- const struct locale_mimo_info *li_mimo;
- const struct locale_info *locale;
- struct brcms_c_info *wlc = wlc_cm->wlc;
- char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
-
- /* save current country state */
- wlc_cm->country = country;
-
- memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
- strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
- BRCM_CNTRY_BUF_SZ - 1);
+ uint size, i;
- strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
- strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
- wlc_cm->regrev = regrev;
+ /* Should just return 0 for single locale driver. */
+ /* Keep it this way in case we add more locales. (for now anyway) */
- /* disable/restore nmode based on country regulations */
- li_mimo = brcms_c_get_mimo_2g(country->locale_mimo_2G);
- if (li_mimo && (li_mimo->flags & BRCMS_NO_MIMO)) {
- brcms_c_set_nmode(wlc, OFF);
- wlc->stf->no_cddstbc = true;
- } else {
- wlc->stf->no_cddstbc = false;
- if (N_ENAB(wlc->pub) != wlc->protection->nmode_user)
- brcms_c_set_nmode(wlc, wlc->protection->nmode_user);
- }
+ /*
+ * all other country def arrays are for regrev == 0, so if
+ * regrev is non-zero, fail
+ */
+ if (regrev > 0)
+ return NULL;
- brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
- brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
- /* set or restore gmode as required by regulatory */
- locale = brcms_c_get_locale_2g(country->locale_2G);
- if (locale && (locale->flags & BRCMS_NO_OFDM)) {
- brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
- } else {
- brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
+ /* find matched table entry from country code */
+ size = ARRAY_SIZE(cntry_locales);
+ for (i = 0; i < size; i++) {
+ if (strcmp(ccode, cntry_locales[i].abbrev) == 0)
+ return &cntry_locales[i].country;
}
-
- brcms_c_channels_init(wlc_cm, country);
-
- return;
-}
-
-/* Lookup a country info structure from a null terminated country code
- * The lookup is case sensitive.
- */
-static const struct country_info *
-brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
-{
- const struct country_info *country;
- char mapped_ccode[BRCM_CNTRY_BUF_SZ];
- uint mapped_regrev;
-
- /* map the country code to a built-in country code, regrev, and country_info struct */
- country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
- &mapped_regrev);
-
- return country;
+ return NULL;
}
static const struct country_info *
@@ -831,174 +703,67 @@ brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode,
return country;
}
-static int
-brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode,
- char *mapped_ccode, uint *mapped_regrev)
-{
- return false;
-}
-
-/* Lookup a country info structure from a null terminated country
- * abbreviation and regrev directly with no translation.
+/* Lookup a country info structure from a null terminated country code
+ * The lookup is case sensitive.
*/
static const struct country_info *
-brcms_c_country_lookup_direct(const char *ccode, uint regrev)
-{
- uint size, i;
-
- /* Should just return 0 for single locale driver. */
- /* Keep it this way in case we add more locales. (for now anyway) */
-
- /* all other country def arrays are for regrev == 0, so if regrev is non-zero, fail */
- if (regrev > 0)
- return NULL;
-
- /* find matched table entry from country code */
- size = ARRAY_SIZE(cntry_locales);
- for (i = 0; i < size; i++) {
- if (strcmp(ccode, cntry_locales[i].abbrev) == 0) {
- return &cntry_locales[i].country;
- }
- }
- return NULL;
-}
-
-static int
-brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
- const struct country_info *country)
-{
- struct brcms_c_info *wlc = wlc_cm->wlc;
- uint i, j;
- struct brcms_band *band;
- const struct locale_info *li;
- chanvec_t sup_chan;
- const struct locale_mimo_info *li_mimo;
-
- band = wlc->band;
- for (i = 0; i < NBANDS(wlc);
- i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
-
- li = BAND_5G(band->bandtype) ?
- brcms_c_get_locale_5g(country->locale_5G) :
- brcms_c_get_locale_2g(country->locale_2G);
- wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
- li_mimo = BAND_5G(band->bandtype) ?
- brcms_c_get_mimo_5g(country->locale_mimo_5G) :
- brcms_c_get_mimo_2g(country->locale_mimo_2G);
-
- /* merge the mimo non-mimo locale flags */
- wlc_cm->bandstate[band->bandunit].locale_flags |=
- li_mimo->flags;
-
- wlc_cm->bandstate[band->bandunit].restricted_channels =
- g_table_restricted_chan[li->restricted_channels];
- wlc_cm->bandstate[band->bandunit].radar_channels =
- g_table_radar_set[li->radar_channels];
-
- /* set the channel availability,
- * masking out the channels that may not be supported on this phy
- */
- wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
- &sup_chan);
- brcms_c_locale_get_channels(li,
- &wlc_cm->bandstate[band->bandunit].
- valid_channels);
- for (j = 0; j < sizeof(chanvec_t); j++)
- wlc_cm->bandstate[band->bandunit].valid_channels.
- vec[j] &= sup_chan.vec[j];
- }
-
- brcms_c_quiet_channels_reset(wlc_cm);
- brcms_c_channels_commit(wlc_cm);
-
- return 0;
-}
-
-/* Update the radio state (enable/disable) and tx power targets
- * based on a new set of channel/regulatory information
- */
-static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
+brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode)
{
- struct brcms_c_info *wlc = wlc_cm->wlc;
- uint chan;
- struct txpwr_limits txpwr;
-
- /* search for the existence of any valid channel */
- for (chan = 0; chan < MAXCHANNEL; chan++) {
- if (VALID_CHANNEL20_DB(wlc, chan)) {
- break;
- }
- }
- if (chan == MAXCHANNEL)
- chan = INVCHANNEL;
-
- /* based on the channel search above, set or clear WL_RADIO_COUNTRY_DISABLE */
- if (chan == INVCHANNEL) {
- /* country/locale with no valid channels, set the radio disable bit */
- mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
- "nbands %d bandlocked %d\n", wlc->pub->unit,
- __func__, wlc_cm->country_abbrev, NBANDS(wlc),
- wlc->bandlocked);
- } else
- if (mboolisset(wlc->pub->radio_disabled,
- WL_RADIO_COUNTRY_DISABLE)) {
- /* country/locale with valid channel, clear the radio disable bit */
- mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
- }
+ const struct country_info *country;
+ char mapped_ccode[BRCM_CNTRY_BUF_SZ];
+ uint mapped_regrev;
- /* Now that the country abbreviation is set, if the radio supports 2G, then
- * set channel 14 restrictions based on the new locale.
+ /*
+ * map the country code to a built-in country code, regrev, and
+ * country_info struct
*/
- if (NBANDS(wlc) > 1 || BAND_2G(wlc->band->bandtype)) {
- wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
- brcms_c_japan(wlc) ? true :
- false);
- }
+ country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode,
+ &mapped_regrev);
- if (wlc->pub->up && chan != INVCHANNEL) {
- brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
- brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
- &txpwr, BRCMS_TXPWR_MAX);
- wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
- }
+ return country;
}
-/* reset the quiet channels vector to the union of the restricted and radar channel sets */
+/*
+ * reset the quiet channels vector to the union
+ * of the restricted and radar channel sets
+ */
static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
uint i, j;
struct brcms_band *band;
- const chanvec_t *chanvec;
+ const struct brcms_chanvec *chanvec;
- memset(&wlc_cm->quiet_channels, 0, sizeof(chanvec_t));
+ memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec));
band = wlc->band;
- for (i = 0; i < NBANDS(wlc);
+ for (i = 0; i < wlc->pub->_nbands;
i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
/* initialize quiet channels for restricted channels */
chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels;
- for (j = 0; j < sizeof(chanvec_t); j++)
+ for (j = 0; j < sizeof(struct brcms_chanvec); j++)
wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j];
}
}
-static bool
-brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, chanspec_t chspec)
+/* Is the channel valid for the current locale and current band? */
+static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+
+ return ((val < MAXCHANNEL) &&
+ isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
+ val));
+}
+
+/* Is the channel valid for the current locale and specified band? */
+static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
+ uint bandunit, uint val)
{
- return N_ENAB(wlc_cm->wlc->pub) && CHSPEC_IS40(chspec) ?
- (isset
- (wlc_cm->quiet_channels.vec,
- LOWER_20_SB(CHSPEC_CHANNEL(chspec)))
- || isset(wlc_cm->quiet_channels.vec,
- UPPER_20_SB(CHSPEC_CHANNEL(chspec)))) : isset(wlc_cm->
- quiet_channels.
- vec,
- CHSPEC_CHANNEL
- (chspec));
+ return ((val < MAXCHANNEL)
+ && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
}
/* Is the channel valid for the current locale? (but don't consider channels not
@@ -1008,27 +773,23 @@ static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
- return VALID_CHANNEL20(wlc, val) ||
+ return brcms_c_valid_channel20(wlc->cmi, val) ||
(!wlc->bandlocked
- && VALID_CHANNEL20_IN_BAND(wlc, OTHERBANDUNIT(wlc), val));
+ && brcms_c_valid_channel20_in_band(wlc->cmi,
+ OTHERBANDUNIT(wlc), val));
}
-/* Is the channel valid for the current locale and specified band? */
-static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm,
- uint bandunit, uint val)
+/* JP, J1 - J10 are Japan ccodes */
+static bool brcms_c_japan_ccode(const char *ccode)
{
- return ((val < MAXCHANNEL)
- && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val));
+ return (ccode[0] == 'J' &&
+ (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
}
-/* Is the channel valid for the current locale and current band? */
-static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val)
+/* Returns true if currently set country is Japan or variant */
+static bool brcms_c_japan(struct brcms_c_info *wlc)
{
- struct brcms_c_info *wlc = wlc_cm->wlc;
-
- return ((val < MAXCHANNEL) &&
- isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec,
- val));
+ return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
}
static void
@@ -1039,50 +800,42 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(
int j;
/* CCK Rates */
- for (j = 0; j < WL_TX_POWER_CCK_NUM; j++) {
+ for (j = 0; j < WL_TX_POWER_CCK_NUM; j++)
txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm);
- }
/* 20 MHz Legacy OFDM SISO */
- for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++) {
+ for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++)
txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm);
- }
/* 20 MHz Legacy OFDM CDD */
- for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
txpwr->ofdm_cdd[j] =
min(txpwr->ofdm_cdd[j], local_constraint_qdbm);
- }
/* 40 MHz Legacy OFDM SISO */
- for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
txpwr->ofdm_40_siso[j] =
min(txpwr->ofdm_40_siso[j], local_constraint_qdbm);
- }
/* 40 MHz Legacy OFDM CDD */
- for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++)
txpwr->ofdm_40_cdd[j] =
min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm);
- }
/* 20MHz MCS 0-7 SISO */
- for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
txpwr->mcs_20_siso[j] =
min(txpwr->mcs_20_siso[j], local_constraint_qdbm);
- }
/* 20MHz MCS 0-7 CDD */
- for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
txpwr->mcs_20_cdd[j] =
min(txpwr->mcs_20_cdd[j], local_constraint_qdbm);
- }
/* 20MHz MCS 0-7 STBC */
- for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
txpwr->mcs_20_stbc[j] =
min(txpwr->mcs_20_stbc[j], local_constraint_qdbm);
- }
/* 20MHz MCS 8-15 MIMO */
for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
@@ -1090,22 +843,19 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(
min(txpwr->mcs_20_mimo[j], local_constraint_qdbm);
/* 40MHz MCS 0-7 SISO */
- for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
txpwr->mcs_40_siso[j] =
min(txpwr->mcs_40_siso[j], local_constraint_qdbm);
- }
/* 40MHz MCS 0-7 CDD */
- for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
txpwr->mcs_40_cdd[j] =
min(txpwr->mcs_40_cdd[j], local_constraint_qdbm);
- }
/* 40MHz MCS 0-7 STBC */
- for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) {
+ for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++)
txpwr->mcs_40_stbc[j] =
min(txpwr->mcs_40_stbc[j], local_constraint_qdbm);
- }
/* 40MHz MCS 8-15 MIMO */
for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++)
@@ -1117,8 +867,276 @@ brcms_c_channel_min_txpower_limits_with_local_constraint(
}
+/* Update the radio state (enable/disable) and tx power targets
+ * based on a new set of channel/regulatory information
+ */
+static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ uint chan;
+ struct txpwr_limits txpwr;
+
+ /* search for the existence of any valid channel */
+ for (chan = 0; chan < MAXCHANNEL; chan++) {
+ if (brcms_c_valid_channel20_db(wlc->cmi, chan))
+ break;
+ }
+ if (chan == MAXCHANNEL)
+ chan = INVCHANNEL;
+
+ /*
+ * based on the channel search above, set or
+ * clear WL_RADIO_COUNTRY_DISABLE.
+ */
+ if (chan == INVCHANNEL) {
+ /*
+ * country/locale with no valid channels, set
+ * the radio disable bit
+ */
+ mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+ wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" "
+ "nbands %d bandlocked %d\n", wlc->pub->unit,
+ __func__, wlc_cm->country_abbrev, wlc->pub->_nbands,
+ wlc->bandlocked);
+ } else if (mboolisset(wlc->pub->radio_disabled,
+ WL_RADIO_COUNTRY_DISABLE)) {
+ /*
+ * country/locale with valid channel, clear
+ * the radio disable bit
+ */
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
+ }
+
+ /*
+ * Now that the country abbreviation is set, if the radio supports 2G,
+ * then set channel 14 restrictions based on the new locale.
+ */
+ if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G)
+ wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi,
+ brcms_c_japan(wlc) ? true :
+ false);
+
+ if (wlc->pub->up && chan != INVCHANNEL) {
+ brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr);
+ brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm,
+ &txpwr, BRCMS_TXPWR_MAX);
+ wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec);
+ }
+}
+
+static int
+brcms_c_channels_init(struct brcms_cm_info *wlc_cm,
+ const struct country_info *country)
+{
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ uint i, j;
+ struct brcms_band *band;
+ const struct locale_info *li;
+ struct brcms_chanvec sup_chan;
+ const struct locale_mimo_info *li_mimo;
+
+ band = wlc->band;
+ for (i = 0; i < wlc->pub->_nbands;
+ i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) {
+
+ li = (band->bandtype == BRCM_BAND_5G) ?
+ brcms_c_get_locale_5g(country->locale_5G) :
+ brcms_c_get_locale_2g(country->locale_2G);
+ wlc_cm->bandstate[band->bandunit].locale_flags = li->flags;
+ li_mimo = (band->bandtype == BRCM_BAND_5G) ?
+ brcms_c_get_mimo_5g(country->locale_mimo_5G) :
+ brcms_c_get_mimo_2g(country->locale_mimo_2G);
+
+ /* merge the mimo non-mimo locale flags */
+ wlc_cm->bandstate[band->bandunit].locale_flags |=
+ li_mimo->flags;
+
+ wlc_cm->bandstate[band->bandunit].restricted_channels =
+ g_table_restricted_chan[li->restricted_channels];
+ wlc_cm->bandstate[band->bandunit].radar_channels =
+ g_table_radar_set[li->radar_channels];
+
+ /*
+ * set the channel availability, masking out the channels
+ * that may not be supported on this phy.
+ */
+ wlc_phy_chanspec_band_validch(band->pi, band->bandtype,
+ &sup_chan);
+ brcms_c_locale_get_channels(li,
+ &wlc_cm->bandstate[band->bandunit].
+ valid_channels);
+ for (j = 0; j < sizeof(struct brcms_chanvec); j++)
+ wlc_cm->bandstate[band->bandunit].valid_channels.
+ vec[j] &= sup_chan.vec[j];
+ }
+
+ brcms_c_quiet_channels_reset(wlc_cm);
+ brcms_c_channels_commit(wlc_cm);
+
+ return 0;
+}
+
+/*
+ * set the driver's current country and regulatory information
+ * using a country code as the source. Look up built in country
+ * information found with the country code.
+ */
+static void
+brcms_c_set_country_common(struct brcms_cm_info *wlc_cm,
+ const char *country_abbrev,
+ const char *ccode, uint regrev,
+ const struct country_info *country)
+{
+ const struct locale_info *locale;
+ struct brcms_c_info *wlc = wlc_cm->wlc;
+ char prev_country_abbrev[BRCM_CNTRY_BUF_SZ];
+
+ /* save current country state */
+ wlc_cm->country = country;
+
+ memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
+ strncpy(prev_country_abbrev, wlc_cm->country_abbrev,
+ BRCM_CNTRY_BUF_SZ - 1);
+
+ strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+ strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+ wlc_cm->regrev = regrev;
+
+ if ((wlc->pub->_n_enab & SUPPORT_11N) !=
+ wlc->protection->nmode_user)
+ brcms_c_set_nmode(wlc);
+
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]);
+ brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]);
+ /* set or restore gmode as required by regulatory */
+ locale = brcms_c_get_locale_2g(country->locale_2G);
+ if (locale && (locale->flags & BRCMS_NO_OFDM))
+ brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
+ else
+ brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
+
+ brcms_c_channels_init(wlc_cm, country);
+
+ return;
+}
+
+static int
+brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm,
+ const char *country_abbrev,
+ const char *ccode, int regrev)
+{
+ const struct country_info *country;
+ char mapped_ccode[BRCM_CNTRY_BUF_SZ];
+ uint mapped_regrev;
+
+ /* if regrev is -1, lookup the mapped country code,
+ * otherwise use the ccode and regrev directly
+ */
+ if (regrev == -1) {
+ /*
+ * map the country code to a built-in country
+ * code, regrev, and country_info
+ */
+ country =
+ brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode,
+ &mapped_regrev);
+ } else {
+ /* find the matching built-in country definition */
+ country = brcms_c_country_lookup_direct(ccode, regrev);
+ strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ);
+ mapped_regrev = regrev;
+ }
+
+ if (country == NULL)
+ return -EINVAL;
+
+ /* set the driver state for the country */
+ brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode,
+ mapped_regrev, country);
+
+ return 0;
+}
+
+/*
+ * set the driver's current country and regulatory information using
+ * a country code as the source. Lookup built in country information
+ * found with the country code.
+ */
+static int
+brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode)
+{
+ char country_abbrev[BRCM_CNTRY_BUF_SZ];
+ strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ);
+ return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1);
+}
+
+struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
+{
+ struct brcms_cm_info *wlc_cm;
+ char country_abbrev[BRCM_CNTRY_BUF_SZ];
+ const struct country_info *country;
+ struct brcms_pub *pub = wlc->pub;
+ char *ccode;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
+ if (wlc_cm == NULL)
+ return NULL;
+ wlc_cm->pub = pub;
+ wlc_cm->wlc = wlc;
+ wlc->cmi = wlc_cm;
+
+ /* store the country code for passing up as a regulatory hint */
+ ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
+ if (ccode)
+ strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+
+ /*
+ * internal country information which must match
+ * regulatory constraints in firmware
+ */
+ memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ);
+ strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1);
+ country = brcms_c_country_lookup(wlc, country_abbrev);
+
+ /* save default country for exiting 11d regulatory mode */
+ strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1);
+
+ /* initialize autocountry_default to driver default */
+ strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1);
+
+ brcms_c_set_countrycode(wlc_cm, country_abbrev);
+
+ return wlc_cm;
+}
+
+void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm)
+{
+ kfree(wlc_cm);
+}
+
+u8
+brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
+ uint bandunit)
+{
+ return wlc_cm->bandstate[bandunit].locale_flags;
+}
+
+static bool
+brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec)
+{
+ return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) &&
+ CHSPEC_IS40(chspec) ?
+ (isset(wlc_cm->quiet_channels.vec,
+ lower_20_sb(CHSPEC_CHANNEL(chspec))) ||
+ isset(wlc_cm->quiet_channels.vec,
+ upper_20_sb(CHSPEC_CHANNEL(chspec)))) :
+ isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec));
+}
+
void
-brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
+brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
u8 local_constraint_qdbm)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
@@ -1126,8 +1144,9 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
- brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm, &txpwr,
- local_constraint_qdbm);
+ brcms_c_channel_min_txpower_limits_with_local_constraint(
+ wlc_cm, &txpwr, local_constraint_qdbm
+ );
brcms_b_set_chanspec(wlc->hw, chanspec,
(brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0),
@@ -1142,112 +1161,100 @@ static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
char fraction[4][4] = { " ", ".25", ".5 ", ".75" };
sprintf(buf, "CCK ");
- for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "20 MHz OFDM SISO ");
- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "20 MHz OFDM CDD ");
- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "40 MHz OFDM SISO ");
- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->ofdm_40_siso[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "40 MHz OFDM CDD ");
- for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->ofdm_40_cdd[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "20 MHz MCS0-7 SISO ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_20_siso[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "20 MHz MCS0-7 CDD ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_20_cdd[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "20 MHz MCS0-7 STBC ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_20_stbc[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "20 MHz MCS8-15 SDM ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_20_mimo[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "40 MHz MCS0-7 SISO ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_40_siso[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "40 MHz MCS0-7 CDD ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_40_cdd[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "40 MHz MCS0-7 STBC ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_40_stbc[i] %
BRCMS_TXPWR_DB_FACTOR]);
- }
printk(KERN_DEBUG "%s\n", buf);
sprintf(buf, "40 MHz MCS8-15 SDM ");
- for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) {
+ for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
sprintf(buf[strlen(buf)], " %2d%s",
txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
fraction[txpwr->mcs_40_mimo[i] %
@@ -1262,7 +1269,7 @@ static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
#endif /* POWER_DBG */
void
-brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
+brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
struct txpwr_limits *txpwr)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
@@ -1273,8 +1280,8 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
const struct country_info *country;
struct brcms_band *band;
const struct locale_info *li;
- int conducted_max;
- int conducted_ofdm_max;
+ int conducted_max = BRCMS_TXPWR_MAX;
+ int conducted_ofdm_max = BRCMS_TXPWR_MAX;
const struct locale_mimo_info *li_mimo;
int maxpwr20, maxpwr40;
int maxpwr_idx;
@@ -1291,12 +1298,12 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
}
chan = CHSPEC_CHANNEL(chanspec);
- band = wlc->bandstate[CHSPEC_BANDUNIT(chanspec)];
- li = BAND_5G(band->bandtype) ?
+ band = wlc->bandstate[chspec_bandunit(chanspec)];
+ li = (band->bandtype == BRCM_BAND_5G) ?
brcms_c_get_locale_5g(country->locale_5G) :
brcms_c_get_locale_2g(country->locale_2G);
- li_mimo = BAND_5G(band->bandtype) ?
+ li_mimo = (band->bandtype == BRCM_BAND_5G) ?
brcms_c_get_mimo_5g(country->locale_mimo_5G) :
brcms_c_get_mimo_2g(country->locale_mimo_2G);
@@ -1314,7 +1321,7 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
}
/* CCK txpwr limits for 2.4G band */
- if (BAND_2G(band->bandtype)) {
+ if (band->bandtype == BRCM_BAND_2G) {
maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)];
maxpwr = maxpwr - delta;
@@ -1326,29 +1333,29 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
}
/* OFDM txpwr limits for 2.4G or 5G bands */
- if (BAND_2G(band->bandtype)) {
+ if (band->bandtype == BRCM_BAND_2G)
maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)];
-
- } else {
+ else
maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)];
- }
maxpwr = maxpwr - delta;
maxpwr = max(maxpwr, 0);
maxpwr = min(maxpwr, conducted_ofdm_max);
/* Keep OFDM lmit below CCK limit */
- if (BAND_2G(band->bandtype))
+ if (band->bandtype == BRCM_BAND_2G)
maxpwr = min_t(int, maxpwr, txpwr->cck[0]);
for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
txpwr->ofdm[i] = (u8) maxpwr;
for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) {
- /* OFDM 40 MHz SISO has the same power as the corresponding MCS0-7 rate unless
- * overriden by the locale specific code. We set this value to 0 as a
- * flag (presumably 0 dBm isn't a possibility) and then copy the MCS0-7 value
- * to the 40 MHz value if it wasn't explicitly set.
+ /*
+ * OFDM 40 MHz SISO has the same power as the corresponding
+ * MCS0-7 rate unless overriden by the locale specific code.
+ * We set this value to 0 as a flag (presumably 0 dBm isn't
+ * a possibility) and then copy the MCS0-7 value to the 40 MHz
+ * value if it wasn't explicitly set.
*/
txpwr->ofdm_40_siso[i] = 0;
@@ -1366,7 +1373,7 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
delta = band->antgain - QDB(6); /* Excess over 6 dB */
}
- if (BAND_2G(band->bandtype))
+ if (band->bandtype == BRCM_BAND_2G)
maxpwr_idx = (chan - 1);
else
maxpwr_idx = CHANNEL_POWER_IDX_5G(chan);
@@ -1382,8 +1389,9 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
/* Fill in the MCS 0-7 (SISO) rates */
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
- /* 20 MHz has the same power as the corresponding OFDM rate unless
- * overriden by the locale specific code.
+ /*
+ * 20 MHz has the same power as the corresponding OFDM rate
+ * unless overriden by the locale specific code.
*/
txpwr->mcs_20_siso[i] = txpwr->ofdm[i];
txpwr->mcs_40_siso[i] = 0;
@@ -1395,15 +1403,17 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
txpwr->mcs_40_cdd[i] = (u8) maxpwr40;
}
- /* These locales have SISO expressed in the table and override CDD later */
+ /*
+ * These locales have SISO expressed in the
+ * table and override CDD later
+ */
if (li_mimo == &locale_bn) {
if (li_mimo == &locale_bn) {
maxpwr20 = QDB(16);
maxpwr40 = 0;
- if (chan >= 3 && chan <= 11) {
+ if (chan >= 3 && chan <= 11)
maxpwr40 = QDB(16);
- }
}
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
@@ -1437,10 +1447,10 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
}
}
- /* Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO value if it wasn't
- * provided explicitly.
+ /*
+ * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO
+ * value if it wasn't provided explicitly.
*/
-
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
if (txpwr->mcs_40_siso[i] == 0)
txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i];
@@ -1456,8 +1466,9 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
}
}
- /* Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding STBC values if they weren't
- * provided explicitly.
+ /*
+ * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding
+ * STBC values if they weren't provided explicitly.
*/
for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) {
if (txpwr->mcs_20_stbc[i] == 0)
@@ -1473,73 +1484,94 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, chanspec_t chanspec,
return;
}
-/* Returns true if currently set country is Japan or variant */
-static bool brcms_c_japan(struct brcms_c_info *wlc)
+/*
+ * Verify the chanspec is using a legal set of parameters, i.e. that the
+ * chanspec specified a band, bw, ctl_sb and channel and that the
+ * combination could be legal given any set of circumstances.
+ * RETURNS: true is the chanspec is malformed, false if it looks good.
+ */
+static bool brcms_c_chspec_malformed(u16 chanspec)
{
- return brcms_c_japan_ccode(wlc->cmi->country_abbrev);
-}
+ /* must be 2G or 5G band */
+ if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
+ return true;
+ /* must be 20 or 40 bandwidth */
+ if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
+ return true;
+
+ /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
+ if (CHSPEC_IS20(chanspec)) {
+ if (!CHSPEC_SB_NONE(chanspec))
+ return true;
+ } else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) {
+ return true;
+ }
-/* JP, J1 - J10 are Japan ccodes */
-static bool brcms_c_japan_ccode(const char *ccode)
-{
- return (ccode[0] == 'J' &&
- (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9')));
+ return false;
}
/*
- * Validate the chanspec for this locale, for 40MHZ we need to also check that the sidebands
- * are valid 20MZH channels in this locale and they are also a legal HT combination
+ * Validate the chanspec for this locale, for 40MHZ we need to also
+ * check that the sidebands are valid 20MZH channels in this locale
+ * and they are also a legal HT combination
*/
static bool
-brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, chanspec_t chspec,
+brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec,
bool dualband)
{
struct brcms_c_info *wlc = wlc_cm->wlc;
u8 channel = CHSPEC_CHANNEL(chspec);
/* check the chanspec */
- if (brcmu_chspec_malformed(chspec)) {
+ if (brcms_c_chspec_malformed(chspec)) {
wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
wlc->pub->unit, chspec);
return false;
}
if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) !=
- CHSPEC_BANDUNIT(chspec))
+ chspec_bandunit(chspec))
return false;
/* Check a 20Mhz channel */
if (CHSPEC_IS20(chspec)) {
if (dualband)
- return VALID_CHANNEL20_DB(wlc_cm->wlc, channel);
+ return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi,
+ channel);
else
- return VALID_CHANNEL20(wlc_cm->wlc, channel);
+ return brcms_c_valid_channel20(wlc_cm->wlc->cmi,
+ channel);
}
#ifdef SUPPORT_40MHZ
- /* We know we are now checking a 40MHZ channel, so we should only be here
- * for NPHYS
+ /*
+ * We know we are now checking a 40MHZ channel, so we should
+ * only be here for NPHYS
*/
if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) {
u8 upper_sideband = 0, idx;
u8 num_ch20_entries =
sizeof(chan20_info) / sizeof(struct chan20_info);
- if (!VALID_40CHANSPEC_IN_BAND(wlc, CHSPEC_BANDUNIT(chspec)))
+ if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec)))
return false;
if (dualband) {
- if (!VALID_CHANNEL20_DB(wlc, LOWER_20_SB(channel)) ||
- !VALID_CHANNEL20_DB(wlc, UPPER_20_SB(channel)))
+ if (!brcms_c_valid_channel20_db(wlc->cmi,
+ lower_20_sb(channel)) ||
+ !brcms_c_valid_channel20_db(wlc->cmi,
+ upper_20_sb(channel)))
return false;
} else {
- if (!VALID_CHANNEL20(wlc, LOWER_20_SB(channel)) ||
- !VALID_CHANNEL20(wlc, UPPER_20_SB(channel)))
+ if (!brcms_c_valid_channel20(wlc->cmi,
+ lower_20_sb(channel)) ||
+ !brcms_c_valid_channel20(wlc->cmi,
+ upper_20_sb(channel)))
return false;
}
/* find the lower sideband info in the sideband array */
for (idx = 0; idx < num_ch20_entries; idx++) {
- if (chan20_info[idx].sb == LOWER_20_SB(channel))
+ if (chan20_info[idx].sb == lower_20_sb(channel))
upper_sideband = chan20_info[idx].adj_sbs;
}
/* check that the lower sideband allows an upper sideband */
@@ -1553,7 +1585,7 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, chanspec_t chspec,
return false;
}
-bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, chanspec_t chspec)
+bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec)
{
return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true);
}
diff --git a/drivers/staging/brcm80211/brcmsmac/channel.h b/drivers/staging/brcm80211/brcmsmac/channel.h
index d22f2f5f592d..808cb4fbfbe7 100644
--- a/drivers/staging/brcm80211/brcmsmac/channel.h
+++ b/drivers/staging/brcm80211/brcmsmac/channel.h
@@ -20,59 +20,6 @@
/* conversion for phy txpwr calculations that use .25 dB units */
#define BRCMS_TXPWR_DB_FACTOR 4
-
-/* maxpwr mapping to 5GHz band channels:
- * maxpwr[0] - channels [34-48]
- * maxpwr[1] - channels [52-60]
- * maxpwr[2] - channels [62-64]
- * maxpwr[3] - channels [100-140]
- * maxpwr[4] - channels [149-165]
- */
-#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */
-
-/* power level in group of 2.4GHz band channels:
- * maxpwr[0] - CCK channels [1]
- * maxpwr[1] - CCK channels [2-10]
- * maxpwr[2] - CCK channels [11-14]
- * maxpwr[3] - OFDM channels [1]
- * maxpwr[4] - OFDM channels [2-10]
- * maxpwr[5] - OFDM channels [11-14]
- */
-
-/* macro to get 2.4 GHz channel group index for tx power */
-#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2)) /* cck index */
-#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5)) /* ofdm index */
-
-/* macro to get 5 GHz channel group index for tx power */
-#define CHANNEL_POWER_IDX_5G(c) \
- (((c) < 52) ? 0 : (((c) < 62) ? 1 : (((c) < 100) ? 2 : (((c) < 149) ? 3 : 4))))
-
-/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */
-#define BRCMS_MAXPWR_TBL_SIZE 6
-/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */
-#define BRCMS_MAXPWR_MIMO_TBL_SIZE 14
-
-#define NBANDS(wlc) ((wlc)->pub->_nbands)
-#define NBANDS_PUB(pub) ((pub)->_nbands)
-#define NBANDS_HW(hw) ((hw)->_nbands)
-
-#define IS_SINGLEBAND_5G(device) 0
-
-/* locale channel and power info. */
-struct locale_info {
- u32 valid_channels;
- /* List of radar sensitive channels */
- u8 radar_channels;
- /* List of channels used only if APs are detected */
- u8 restricted_channels;
- /* Max tx pwr in qdBm for each sub-band */
- s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE];
- s8 pub_maxpwr[BAND_5G_PWR_LVLS]; /* Country IE advertised max tx pwr in dBm
- * per sub-band
- */
- u8 flags;
-};
-
/* bits for locale_info flags */
#define BRCMS_PEAK_CONDUCTED 0x00 /* Peak for locals */
#define BRCMS_EIRP 0x01 /* Flag for EIRP */
@@ -82,34 +29,8 @@ struct locale_info {
#define BRCMS_NO_MIMO 0x10 /* Flag for No MIMO, 20 or 40 MHz */
#define BRCMS_RADAR_TYPE_EU 0x20 /* Flag for EU */
#define BRCMS_DFS_FCC BRCMS_DFS_TPC /* Flag for DFS FCC */
-#define BRCMS_DFS_EU (BRCMS_DFS_TPC | BRCMS_RADAR_TYPE_EU) /* Flag for DFS EU */
-
-#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU)
-
-/* locale per-channel tx power limits for MIMO frames
- * maxpwr arrays are index by channel for 2.4 GHz limits, and
- * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel)
- */
-struct locale_mimo_info {
- /* tx 20 MHz power limits, qdBm units */
- s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE];
- /* tx 40 MHz power limits, qdBm units */
- s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE];
- u8 flags;
-};
-extern const chanvec_t chanvec_all_2G;
-extern const chanvec_t chanvec_all_5G;
-
-/*
- * Country names and abbreviations with locale defined from ISO 3166
- */
-struct country_info {
- const u8 locale_2G; /* 2.4G band locale */
- const u8 locale_5G; /* 5G band locale */
- const u8 locale_mimo_2G; /* 2.4G mimo info */
- const u8 locale_mimo_5G; /* 5G mimo info */
-};
+#define BRCMS_DFS_EU (BRCMS_DFS_TPC | BRCMS_RADAR_TYPE_EU) /* Flag for DFS EU */
extern struct brcms_cm_info *
brcms_c_channel_mgr_attach(struct brcms_c_info *wlc);
@@ -120,13 +41,13 @@ extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm,
uint bandunit);
extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm,
- chanspec_t chspec);
+ u16 chspec);
extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm,
- chanspec_t chanspec,
+ u16 chanspec,
struct txpwr_limits *txpwr);
extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm,
- chanspec_t chanspec,
+ u16 chanspec,
u8 local_constraint_qdbm);
#endif /* _WLC_CHANNEL_H */
diff --git a/drivers/staging/brcm80211/brcmsmac/d11.h b/drivers/staging/brcm80211/brcmsmac/d11.h
index e7ff0e6f28e0..ed51616abc85 100644
--- a/drivers/staging/brcm80211/brcmsmac/d11.h
+++ b/drivers/staging/brcm80211/brcmsmac/d11.h
@@ -23,17 +23,15 @@
#include "pub.h"
#include "dma.h"
-#define BCN_TMPL_LEN 512 /* length of the BCN template area */
-
/* RX FIFO numbers */
#define RX_FIFO 0 /* data and ctl frames */
#define RX_TXSTATUS_FIFO 3 /* RX fifo for tx status packages */
-/* TX FIFO numbers using WME Access Classes */
-#define TX_AC_BK_FIFO 0 /* Access Category Background TX FIFO */
-#define TX_AC_BE_FIFO 1 /* Access Category Best-Effort TX FIFO */
-#define TX_AC_VI_FIFO 2 /* Access Class Video TX FIFO */
-#define TX_AC_VO_FIFO 3 /* Access Class Voice TX FIFO */
+/* TX FIFO numbers using WME Access Category */
+#define TX_AC_BK_FIFO 0 /* Background TX FIFO */
+#define TX_AC_BE_FIFO 1 /* Best-Effort TX FIFO */
+#define TX_AC_VI_FIFO 2 /* Video TX FIFO */
+#define TX_AC_VO_FIFO 3 /* Voice TX FIFO */
#define TX_BCMC_FIFO 4 /* Broadcast/Multicast TX FIFO */
#define TX_ATIM_FIFO 5 /* TX fifo for ATIM window info */
@@ -47,11 +45,7 @@
#define TX_DATA_FIFO TX_AC_BE_FIFO
#define TX_CTL_FIFO TX_AC_VO_FIFO
-#ifndef WL_RSSI_ANT_MAX
#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */
-#elif WL_RSSI_ANT_MAX != 4
-#error "WL_RSSI_ANT_MAX does not match"
-#endif
struct intctrlregs {
u32 intstatus;
@@ -73,8 +67,8 @@ struct pio2regs {
/* a pair of pio channels(tx and rx) */
struct pio2regp {
- pio2regs_t tx;
- pio2regs_t rx;
+ struct pio2regs tx;
+ struct pio2regs rx;
};
/* 4byte-wide pio register set per channel(xmt or rcv) */
@@ -85,8 +79,8 @@ struct pio4regs {
/* a pair of pio channels(tx and rx) */
struct pio4regp {
- pio4regs_t tx;
- pio4regs_t rx;
+ struct pio4regs tx;
+ struct pio4regs rx;
};
/* read: 32-bit register that can be read as 32-bit or as 2 16-bit
@@ -101,10 +95,10 @@ union pmqreg {
};
struct fifo64 {
- dma64regs_t dmaxmt; /* dma tx */
- pio4regs_t piotx; /* pio tx */
- dma64regs_t dmarcv; /* dma rx */
- pio4regs_t piorx; /* pio rx */
+ struct dma64regs dmaxmt; /* dma tx */
+ struct pio4regs piotx; /* pio tx */
+ struct dma64regs dmarcv; /* dma rx */
+ struct pio4regs piorx; /* pio rx */
};
/*
@@ -120,7 +114,7 @@ struct d11regs {
u32 usectimer; /* 0x1c *//* for corerev >= 26 */
/* Interrupt Control *//* 0x20 */
- intctrlregs_t intctrlregs[8];
+ struct intctrlregs intctrlregs[8];
u32 PAD[40]; /* 0x60 - 0xFC */
@@ -139,7 +133,7 @@ struct d11regs {
u32 PAD[2]; /* 0x138 - 0x13C */
/* PMQ registers */
- pmqreg_t pmqreg; /* 0x140 */
+ union pmqreg pmqreg; /* 0x140 */
u32 pmqpatl; /* 0x144 */
u32 pmqpath; /* 0x148 */
u32 PAD; /* 0x14C */
@@ -179,10 +173,10 @@ struct d11regs {
u32 PAD[5]; /* 0x1ec - 0x1fc */
/* 0x200-0x37F dma/pio registers */
- fifo64_t fifo64regs[6];
+ struct fifo64 fifo64regs[6];
/* FIFO diagnostic port access */
- dma32diag_t dmafifo; /* 0x380 - 0x38C */
+ struct dma32diag dmafifo; /* 0x380 - 0x38C */
u32 aggfifocnt; /* 0x390 */
u32 aggfifodata; /* 0x394 */
@@ -457,7 +451,7 @@ struct d11regs {
#define IRL_FC_MASK 0xff000000 /* frame count */
#define IRL_FC_SHIFT 24 /* frame count */
-/* maccontrol register */
+/*== maccontrol register ==*/
#define MCTL_GMODE (1U << 31)
#define MCTL_DISCARD_PMQ (1 << 30)
#define MCTL_WAKE (1 << 26)
@@ -481,75 +475,119 @@ struct d11regs {
#define MCTL_PSM_RUN (1 << 1)
#define MCTL_EN_MAC (1 << 0)
-/* maccommand register */
+/*== maccommand register ==*/
#define MCMD_BCN0VLD (1 << 0)
#define MCMD_BCN1VLD (1 << 1)
#define MCMD_DIRFRMQVAL (1 << 2)
#define MCMD_CCA (1 << 3)
#define MCMD_BG_NOISE (1 << 4)
#define MCMD_SKIP_SHMINIT (1 << 5) /* only used for simulation */
-#define MCMD_SAMPLECOLL MCMD_SKIP_SHMINIT /* reuse for sample collect */
-
-/* macintstatus/macintmask */
-#define MI_MACSSPNDD (1 << 0) /* MAC has gracefully suspended */
-#define MI_BCNTPL (1 << 1) /* beacon template available */
-#define MI_TBTT (1 << 2) /* TBTT indication */
-#define MI_BCNSUCCESS (1 << 3) /* beacon successfully tx'd */
-#define MI_BCNCANCLD (1 << 4) /* beacon canceled (IBSS) */
-#define MI_ATIMWINEND (1 << 5) /* end of ATIM-window (IBSS) */
-#define MI_PMQ (1 << 6) /* PMQ entries available */
-#define MI_NSPECGEN_0 (1 << 7) /* non-specific gen-stat bits that are set by PSM */
-#define MI_NSPECGEN_1 (1 << 8) /* non-specific gen-stat bits that are set by PSM */
-#define MI_MACTXERR (1 << 9) /* MAC level Tx error */
-#define MI_NSPECGEN_3 (1 << 10) /* non-specific gen-stat bits that are set by PSM */
-#define MI_PHYTXERR (1 << 11) /* PHY Tx error */
-#define MI_PME (1 << 12) /* Power Management Event */
-#define MI_GP0 (1 << 13) /* General-purpose timer0 */
-#define MI_GP1 (1 << 14) /* General-purpose timer1 */
-#define MI_DMAINT (1 << 15) /* (ORed) DMA-interrupts */
-#define MI_TXSTOP (1 << 16) /* MAC has completed a TX FIFO Suspend/Flush */
-#define MI_CCA (1 << 17) /* MAC has completed a CCA measurement */
-#define MI_BG_NOISE (1 << 18) /* MAC has collected background noise samples */
-#define MI_DTIM_TBTT (1 << 19) /* MBSS DTIM TBTT indication */
-#define MI_PRQ (1 << 20) /* Probe response queue needs attention */
-#define MI_PWRUP (1 << 21) /* Radio/PHY has been powered back up. */
+#define MCMD_SAMPLECOLL MCMD_SKIP_SHMINIT /* reuse for sample collect */
+
+/*== macintstatus/macintmask ==*/
+/* gracefully suspended */
+#define MI_MACSSPNDD (1 << 0)
+/* beacon template available */
+#define MI_BCNTPL (1 << 1)
+/* TBTT indication */
+#define MI_TBTT (1 << 2)
+/* beacon successfully tx'd */
+#define MI_BCNSUCCESS (1 << 3)
+/* beacon canceled (IBSS) */
+#define MI_BCNCANCLD (1 << 4)
+/* end of ATIM-window (IBSS) */
+#define MI_ATIMWINEND (1 << 5)
+/* PMQ entries available */
+#define MI_PMQ (1 << 6)
+/* non-specific gen-stat bits that are set by PSM */
+#define MI_NSPECGEN_0 (1 << 7)
+/* non-specific gen-stat bits that are set by PSM */
+#define MI_NSPECGEN_1 (1 << 8)
+/* MAC level Tx error */
+#define MI_MACTXERR (1 << 9)
+/* non-specific gen-stat bits that are set by PSM */
+#define MI_NSPECGEN_3 (1 << 10)
+/* PHY Tx error */
+#define MI_PHYTXERR (1 << 11)
+/* Power Management Event */
+#define MI_PME (1 << 12)
+/* General-purpose timer0 */
+#define MI_GP0 (1 << 13)
+/* General-purpose timer1 */
+#define MI_GP1 (1 << 14)
+/* (ORed) DMA-interrupts */
+#define MI_DMAINT (1 << 15)
+/* MAC has completed a TX FIFO Suspend/Flush */
+#define MI_TXSTOP (1 << 16)
+/* MAC has completed a CCA measurement */
+#define MI_CCA (1 << 17)
+/* MAC has collected background noise samples */
+#define MI_BG_NOISE (1 << 18)
+/* MBSS DTIM TBTT indication */
+#define MI_DTIM_TBTT (1 << 19)
+/* Probe response queue needs attention */
+#define MI_PRQ (1 << 20)
+/* Radio/PHY has been powered back up. */
+#define MI_PWRUP (1 << 21)
#define MI_RESERVED3 (1 << 22)
#define MI_RESERVED2 (1 << 23)
#define MI_RESERVED1 (1 << 25)
/* MAC detected change on RF Disable input*/
#define MI_RFDISABLE (1 << 28)
-#define MI_TFS (1 << 29) /* MAC has completed a TX */
-#define MI_PHYCHANGED (1 << 30) /* A phy status change wrt G mode */
-#define MI_TO (1U << 31) /* general purpose timeout */
+/* MAC has completed a TX */
+#define MI_TFS (1 << 29)
+/* A phy status change wrt G mode */
+#define MI_PHYCHANGED (1 << 30)
+/* general purpose timeout */
+#define MI_TO (1U << 31)
/* Mac capabilities registers */
-/* machwcap */
+/*== machwcap ==*/
#define MCAP_TKIPMIC 0x80000000 /* TKIP MIC hardware present */
-/* pmqhost data */
-#define PMQH_DATA_MASK 0xffff0000 /* data entry of head pmq entry */
-#define PMQH_BSSCFG 0x00100000 /* PM entry for BSS config */
-#define PMQH_PMOFF 0x00010000 /* PM Mode OFF: power save off */
-#define PMQH_PMON 0x00020000 /* PM Mode ON: power save on */
-#define PMQH_DASAT 0x00040000 /* Dis-associated or De-authenticated */
-#define PMQH_ATIMFAIL 0x00080000 /* ATIM not acknowledged */
-#define PMQH_DEL_ENTRY 0x00000001 /* delete head entry */
-#define PMQH_DEL_MULT 0x00000002 /* delete head entry to cur read pointer -1 */
-#define PMQH_OFLO 0x00000004 /* pmq overflow indication */
-#define PMQH_NOT_EMPTY 0x00000008 /* entries are present in pmq */
-
-/* phydebug */
-#define PDBG_CRS (1 << 0) /* phy is asserting carrier sense */
-#define PDBG_TXA (1 << 1) /* phy is taking xmit byte from mac this cycle */
-#define PDBG_TXF (1 << 2) /* mac is instructing the phy to transmit a frame */
-#define PDBG_TXE (1 << 3) /* phy is signalling a transmit Error to the mac */
-#define PDBG_RXF (1 << 4) /* phy detected the end of a valid frame preamble */
-#define PDBG_RXS (1 << 5) /* phy detected the end of a valid PLCP header */
-#define PDBG_RXFRG (1 << 6) /* rx start not asserted */
-#define PDBG_RXV (1 << 7) /* mac is taking receive byte from phy this cycle */
-#define PDBG_RFD (1 << 16) /* RF portion of the radio is disabled */
-
-/* objaddr register */
+/*== pmqhost data ==*/
+/* data entry of head pmq entry */
+#define PMQH_DATA_MASK 0xffff0000
+/* PM entry for BSS config */
+#define PMQH_BSSCFG 0x00100000
+/* PM Mode OFF: power save off */
+#define PMQH_PMOFF 0x00010000
+/* PM Mode ON: power save on */
+#define PMQH_PMON 0x00020000
+/* Dis-associated or De-authenticated */
+#define PMQH_DASAT 0x00040000
+/* ATIM not acknowledged */
+#define PMQH_ATIMFAIL 0x00080000
+/* delete head entry */
+#define PMQH_DEL_ENTRY 0x00000001
+/* delete head entry to cur read pointer -1 */
+#define PMQH_DEL_MULT 0x00000002
+/* pmq overflow indication */
+#define PMQH_OFLO 0x00000004
+/* entries are present in pmq */
+#define PMQH_NOT_EMPTY 0x00000008
+
+/*== phydebug ==*/
+/* phy is asserting carrier sense */
+#define PDBG_CRS (1 << 0)
+/* phy is taking xmit byte from mac this cycle */
+#define PDBG_TXA (1 << 1)
+/* mac is instructing the phy to transmit a frame */
+#define PDBG_TXF (1 << 2)
+/* phy is signalling a transmit Error to the mac */
+#define PDBG_TXE (1 << 3)
+/* phy detected the end of a valid frame preamble */
+#define PDBG_RXF (1 << 4)
+/* phy detected the end of a valid PLCP header */
+#define PDBG_RXS (1 << 5)
+/* rx start not asserted */
+#define PDBG_RXFRG (1 << 6)
+/* mac is taking receive byte from phy this cycle */
+#define PDBG_RXV (1 << 7)
+/* RF portion of the radio is disabled */
+#define PDBG_RFD (1 << 16)
+
+/*== objaddr register ==*/
#define OBJADDR_SEL_MASK 0x000F0000
#define OBJADDR_UCM_SEL 0x00000000
#define OBJADDR_SHM_SEL 0x00010000
@@ -564,20 +602,20 @@ struct d11regs {
#define WEP_PCMADDR 0x07d4
#define WEP_PCMDATA 0x07d6
-/* frmtxstatus */
+/*== frmtxstatus ==*/
#define TXS_V (1 << 0) /* valid bit */
#define TXS_STATUS_MASK 0xffff
#define TXS_FID_MASK 0xffff0000
#define TXS_FID_SHIFT 16
-/* frmtxstatus2 */
+/*== frmtxstatus2 ==*/
#define TXS_SEQ_MASK 0xffff
#define TXS_PTX_MASK 0xff0000
#define TXS_PTX_SHIFT 16
#define TXS_MU_MASK 0x01000000
#define TXS_MU_SHIFT 24
-/* clk_ctl_st */
+/*== clk_ctl_st ==*/
#define CCS_ERSRC_REQ_D11PLL 0x00000100 /* d11 core pll request */
#define CCS_ERSRC_REQ_PHYPLL 0x00000200 /* PHY pll request */
#define CCS_ERSRC_AVAIL_D11PLL 0x01000000 /* d11 core pll available */
@@ -602,22 +640,27 @@ struct d11regs {
#define TXFIFO_SIZE_UNIT 256 /* one unit corresponds to 256 bytes */
#define MBSS16_TEMPLMEM_MINBLKS 65 /* one unit corresponds to 256 bytes */
-/* phy versions, PhyVersion:Revision field */
-#define PV_AV_MASK 0xf000 /* analog block version */
-#define PV_AV_SHIFT 12 /* analog block version bitfield offset */
-#define PV_PT_MASK 0x0f00 /* phy type */
-#define PV_PT_SHIFT 8 /* phy type bitfield offset */
-#define PV_PV_MASK 0x000f /* phy version */
+/*== phy versions (PhyVersion:Revision field) ==*/
+/* analog block version */
+#define PV_AV_MASK 0xf000
+/* analog block version bitfield offset */
+#define PV_AV_SHIFT 12
+/* phy type */
+#define PV_PT_MASK 0x0f00
+/* phy type bitfield offset */
+#define PV_PT_SHIFT 8
+/* phy version */
+#define PV_PV_MASK 0x000f
#define PHY_TYPE(v) ((v & PV_PT_MASK) >> PV_PT_SHIFT)
-/* phy types, PhyVersion:PhyType field */
+/*== phy types (PhyVersion:PhyType field) ==*/
#define PHY_TYPE_N 4 /* N-Phy value */
#define PHY_TYPE_SSN 6 /* SSLPN-Phy value */
#define PHY_TYPE_LCN 8 /* LCN-Phy value */
#define PHY_TYPE_LCNXN 9 /* LCNXN-Phy value */
#define PHY_TYPE_NULL 0xf /* Invalid Phy value */
-/* analog types, PhyVersion:AnalogType field */
+/*== analog types (PhyVersion:AnalogType field) ==*/
#define ANA_11N_013 5
/* 802.11a PLCP header def */
@@ -693,45 +736,46 @@ struct cck_phy_hdr {
#define BRCMS_CLR_MIMO_PLCP_AMPDU(plcp) (plcp[3] &= ~MIMO_PLCP_AMPDU)
#define BRCMS_IS_MIMO_PLCP_AMPDU(plcp) (plcp[3] & MIMO_PLCP_AMPDU)
-/* The dot11a PLCP header is 5 bytes. To simplify the software (so that we
- * don't need e.g. different tx DMA headers for 11a and 11b), the PLCP header has
- * padding added in the ucode.
+/*
+ * The dot11a PLCP header is 5 bytes. To simplify the software (so that we
+ * don't need e.g. different tx DMA headers for 11a and 11b), the PLCP header
+ * has padding added in the ucode.
*/
#define D11_PHY_HDR_LEN 6
/* TX DMA buffer header */
struct d11txh {
- u16 MacTxControlLow; /* 0x0 */
- u16 MacTxControlHigh; /* 0x1 */
- u16 MacFrameControl; /* 0x2 */
- u16 TxFesTimeNormal; /* 0x3 */
- u16 PhyTxControlWord; /* 0x4 */
- u16 PhyTxControlWord_1; /* 0x5 */
- u16 PhyTxControlWord_1_Fbr; /* 0x6 */
- u16 PhyTxControlWord_1_Rts; /* 0x7 */
- u16 PhyTxControlWord_1_FbrRts; /* 0x8 */
- u16 MainRates; /* 0x9 */
- u16 XtraFrameTypes; /* 0xa */
+ __le16 MacTxControlLow; /* 0x0 */
+ __le16 MacTxControlHigh; /* 0x1 */
+ __le16 MacFrameControl; /* 0x2 */
+ __le16 TxFesTimeNormal; /* 0x3 */
+ __le16 PhyTxControlWord; /* 0x4 */
+ __le16 PhyTxControlWord_1; /* 0x5 */
+ __le16 PhyTxControlWord_1_Fbr; /* 0x6 */
+ __le16 PhyTxControlWord_1_Rts; /* 0x7 */
+ __le16 PhyTxControlWord_1_FbrRts; /* 0x8 */
+ __le16 MainRates; /* 0x9 */
+ __le16 XtraFrameTypes; /* 0xa */
u8 IV[16]; /* 0x0b - 0x12 */
u8 TxFrameRA[6]; /* 0x13 - 0x15 */
- u16 TxFesTimeFallback; /* 0x16 */
+ __le16 TxFesTimeFallback; /* 0x16 */
u8 RTSPLCPFallback[6]; /* 0x17 - 0x19 */
- u16 RTSDurFallback; /* 0x1a */
+ __le16 RTSDurFallback; /* 0x1a */
u8 FragPLCPFallback[6]; /* 0x1b - 1d */
- u16 FragDurFallback; /* 0x1e */
- u16 MModeLen; /* 0x1f */
- u16 MModeFbrLen; /* 0x20 */
- u16 TstampLow; /* 0x21 */
- u16 TstampHigh; /* 0x22 */
- u16 ABI_MimoAntSel; /* 0x23 */
- u16 PreloadSize; /* 0x24 */
- u16 AmpduSeqCtl; /* 0x25 */
- u16 TxFrameID; /* 0x26 */
- u16 TxStatus; /* 0x27 */
- u16 MaxNMpdus; /* 0x28 */
- u16 MaxABytes_MRT; /* 0x29 */
- u16 MaxABytes_FBR; /* 0x2a */
- u16 MinMBytes; /* 0x2b */
+ __le16 FragDurFallback; /* 0x1e */
+ __le16 MModeLen; /* 0x1f */
+ __le16 MModeFbrLen; /* 0x20 */
+ __le16 TstampLow; /* 0x21 */
+ __le16 TstampHigh; /* 0x22 */
+ __le16 ABI_MimoAntSel; /* 0x23 */
+ __le16 PreloadSize; /* 0x24 */
+ __le16 AmpduSeqCtl; /* 0x25 */
+ __le16 TxFrameID; /* 0x26 */
+ __le16 TxStatus; /* 0x27 */
+ __le16 MaxNMpdus; /* 0x28 */
+ __le16 MaxABytes_MRT; /* 0x29 */
+ __le16 MaxABytes_FBR; /* 0x2a */
+ __le16 MinMBytes; /* 0x2b */
u8 RTSPhyHeader[D11_PHY_HDR_LEN]; /* 0x2c - 0x2e */
struct ieee80211_rts rts_frame; /* 0x2f - 0x36 */
u16 PAD; /* 0x37 */
@@ -745,14 +789,17 @@ struct d11txh {
#define FT_HT 2
#define FT_N 3
-/* Position of MPDU inside A-MPDU; indicated with bits 10:9 of MacTxControlLow */
+/*
+ * Position of MPDU inside A-MPDU; indicated with bits 10:9
+ * of MacTxControlLow
+ */
#define TXC_AMPDU_SHIFT 9 /* shift for ampdu settings */
#define TXC_AMPDU_NONE 0 /* Regular MPDU, not an A-MPDU */
#define TXC_AMPDU_FIRST 1 /* first MPDU of an A-MPDU */
#define TXC_AMPDU_MIDDLE 2 /* intermediate MPDU of an A-MPDU */
#define TXC_AMPDU_LAST 3 /* last (or single) MPDU of an A-MPDU */
-/* MacTxControlLow */
+/*== MacTxControlLow ==*/
#define TXC_AMIC 0x8000
#define TXC_SENDCTS 0x0800
#define TXC_AMPDU_MASK 0x0600
@@ -766,18 +813,25 @@ struct d11txh {
#define TXC_LONGFRAME 0x0002
#define TXC_IMMEDACK 0x0001
-/* MacTxControlHigh */
-#define TXC_PREAMBLE_RTS_FB_SHORT 0x8000 /* RTS fallback preamble type 1 = SHORT 0 = LONG */
-#define TXC_PREAMBLE_RTS_MAIN_SHORT 0x4000 /* RTS main rate preamble type 1 = SHORT 0 = LONG */
-#define TXC_PREAMBLE_DATA_FB_SHORT 0x2000 /* Main fallback rate preamble type
- * 1 = SHORT for OFDM/GF for MIMO
- * 0 = LONG for CCK/MM for MIMO
- */
+/*== MacTxControlHigh ==*/
+/* RTS fallback preamble type 1 = SHORT 0 = LONG */
+#define TXC_PREAMBLE_RTS_FB_SHORT 0x8000
+/* RTS main rate preamble type 1 = SHORT 0 = LONG */
+#define TXC_PREAMBLE_RTS_MAIN_SHORT 0x4000
+/*
+ * Main fallback rate preamble type
+ * 1 = SHORT for OFDM/GF for MIMO
+ * 0 = LONG for CCK/MM for MIMO
+ */
+#define TXC_PREAMBLE_DATA_FB_SHORT 0x2000
+
/* TXC_PREAMBLE_DATA_MAIN is in PhyTxControl bit 5 */
-#define TXC_AMPDU_FBR 0x1000 /* use fallback rate for this AMPDU */
+/* use fallback rate for this AMPDU */
+#define TXC_AMPDU_FBR 0x1000
#define TXC_SECKEY_MASK 0x0FF0
#define TXC_SECKEY_SHIFT 4
-#define TXC_ALT_TXPWR 0x0008 /* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */
+/* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */
+#define TXC_ALT_TXPWR 0x0008
#define TXC_SECTYPE_MASK 0x0007
#define TXC_SECTYPE_SHIFT 0
@@ -817,7 +871,7 @@ struct d11txh {
#define PHY_TXC1_MODE_SDM 3
/* PhyTxControl for HTphy that are different from Mimophy */
-#define PHY_TXC_HTANT_MASK 0x3fC0 /* bit 6, 7, 8, 9, 10, 11, 12, 13 */
+#define PHY_TXC_HTANT_MASK 0x3fC0 /* bits 6-13 */
/* XtraFrameTypes */
#define XFTS_RTS_FT_SHIFT 2
@@ -862,23 +916,23 @@ struct tx_status {
#define TX_STATUS_RTS_RTX_MASK 0x0F00
#define TX_STATUS_RTS_RTX_SHIFT 8
#define TX_STATUS_MASK 0x00FE
-#define TX_STATUS_PMINDCTD (1 << 7) /* PM mode indicated to AP */
-#define TX_STATUS_INTERMEDIATE (1 << 6) /* intermediate or 1st ampdu pkg */
-#define TX_STATUS_AMPDU (1 << 5) /* AMPDU status */
-#define TX_STATUS_SUPR_MASK 0x1C /* suppress status bits (4:2) */
+#define TX_STATUS_PMINDCTD (1 << 7) /* PM mode indicated to AP */
+#define TX_STATUS_INTERMEDIATE (1 << 6) /* intermediate or 1st ampdu pkg */
+#define TX_STATUS_AMPDU (1 << 5) /* AMPDU status */
+#define TX_STATUS_SUPR_MASK 0x1C /* suppress status bits (4:2) */
#define TX_STATUS_SUPR_SHIFT 2
-#define TX_STATUS_ACK_RCV (1 << 1) /* ACK received */
-#define TX_STATUS_VALID (1 << 0) /* Tx status valid */
+#define TX_STATUS_ACK_RCV (1 << 1) /* ACK received */
+#define TX_STATUS_VALID (1 << 0) /* Tx status valid */
#define TX_STATUS_NO_ACK 0
/* suppress status reason codes */
-#define TX_STATUS_SUPR_PMQ (1 << 2) /* PMQ entry */
-#define TX_STATUS_SUPR_FLUSH (2 << 2) /* flush request */
-#define TX_STATUS_SUPR_FRAG (3 << 2) /* previous frag failure */
-#define TX_STATUS_SUPR_TBTT (3 << 2) /* SHARED: Probe response supr for TBTT */
-#define TX_STATUS_SUPR_BADCH (4 << 2) /* channel mismatch */
-#define TX_STATUS_SUPR_EXPTIME (5 << 2) /* lifetime expiry */
-#define TX_STATUS_SUPR_UF (6 << 2) /* underflow */
+#define TX_STATUS_SUPR_PMQ (1 << 2) /* PMQ entry */
+#define TX_STATUS_SUPR_FLUSH (2 << 2) /* flush request */
+#define TX_STATUS_SUPR_FRAG (3 << 2) /* previous frag failure */
+#define TX_STATUS_SUPR_TBTT (3 << 2) /* SHARED: Probe resp supr for TBTT */
+#define TX_STATUS_SUPR_BADCH (4 << 2) /* channel mismatch */
+#define TX_STATUS_SUPR_EXPTIME (5 << 2) /* lifetime expiry */
+#define TX_STATUS_SUPR_UF (6 << 2) /* underflow */
/* Unexpected tx status for rate update */
#define TX_STATUS_UNEXP(status) \
@@ -939,8 +993,8 @@ struct tx_status {
#define ADDR_BMP_RA (1 << 0) /* Receiver Address (RA) */
#define ADDR_BMP_TA (1 << 1) /* Transmitter Address (TA) */
#define ADDR_BMP_BSSID (1 << 2) /* BSSID */
-#define ADDR_BMP_AP (1 << 3) /* Infra-BSS Access Point (AP) */
-#define ADDR_BMP_STA (1 << 4) /* Infra-BSS Station (STA) */
+#define ADDR_BMP_AP (1 << 3) /* Infra-BSS Access Point */
+#define ADDR_BMP_STA (1 << 4) /* Infra-BSS Station */
#define ADDR_BMP_RESERVED1 (1 << 5)
#define ADDR_BMP_RESERVED2 (1 << 6)
#define ADDR_BMP_RESERVED3 (1 << 7)
@@ -1012,9 +1066,10 @@ struct tx_status {
#define T_BCN0_TPL_BASE (0x34 * 2)
#define T_PRS_TPL_BASE (0x134 * 2)
#define T_BCN1_TPL_BASE (0x234 * 2)
-#define T_TX_FIFO_TXRAM_BASE (T_ACTS_TPL_BASE + (TXFIFO_START_BLK * TXFIFO_SIZE_UNIT))
+#define T_TX_FIFO_TXRAM_BASE (T_ACTS_TPL_BASE + \
+ (TXFIFO_START_BLK * TXFIFO_SIZE_UNIT))
-#define T_BA_TPL_BASE T_QNULL_TPL_BASE /* template area for BA */
+#define T_BA_TPL_BASE T_QNULL_TPL_BASE /* template area for BA */
#define T_RAM_ACCESS_SZ 4 /* template ram is 4 byte access only */
@@ -1207,14 +1262,18 @@ struct tx_status {
#define WATCHDOG_8TU_MAX 10
/* Manufacturing Test Variables */
-#define M_PKTENG_CTRL (0x6c * 2) /* PER test mode */
-#define M_PKTENG_IFS (0x6d * 2) /* IFS for TX mode */
-#define M_PKTENG_FRMCNT_LO (0x6e * 2) /* Lower word of tx frmcnt/rx lostcnt */
-#define M_PKTENG_FRMCNT_HI (0x6f * 2) /* Upper word of tx frmcnt/rx lostcnt */
+/* PER test mode */
+#define M_PKTENG_CTRL (0x6c * 2)
+/* IFS for TX mode */
+#define M_PKTENG_IFS (0x6d * 2)
+/* Lower word of tx frmcnt/rx lostcnt */
+#define M_PKTENG_FRMCNT_LO (0x6e * 2)
+/* Upper word of tx frmcnt/rx lostcnt */
+#define M_PKTENG_FRMCNT_HI (0x6f * 2)
/* Index variation in vbat ripple */
-#define M_LCN_PWR_IDX_MAX (0x67 * 2) /* highest index read by ucode */
-#define M_LCN_PWR_IDX_MIN (0x66 * 2) /* lowest index read by ucode */
+#define M_LCN_PWR_IDX_MAX (0x67 * 2) /* highest index read by ucode */
+#define M_LCN_PWR_IDX_MIN (0x66 * 2) /* lowest index read by ucode */
/* M_PKTENG_CTRL bit definitions */
#define M_PKTENG_MODE_TX 0x0001
@@ -1223,11 +1282,14 @@ struct tx_status {
#define M_PKTENG_MODE_RX 0x0002
#define M_PKTENG_MODE_RX_WITH_ACK 0x0402
#define M_PKTENG_MODE_MASK 0x0003
-#define M_PKTENG_FRMCNT_VLD 0x0100 /* TX frames indicated in the frmcnt reg */
+/* TX frames indicated in the frmcnt reg */
+#define M_PKTENG_FRMCNT_VLD 0x0100
/* Sample Collect parameters (bitmap and type) */
-#define M_SMPL_COL_BMP (0x37d * 2) /* Trigger bitmap for sample collect */
-#define M_SMPL_COL_CTL (0x3b2 * 2) /* Sample collect type */
+/* Trigger bitmap for sample collect */
+#define M_SMPL_COL_BMP (0x37d * 2)
+/* Sample collect type */
+#define M_SMPL_COL_CTL (0x3b2 * 2)
#define ANTSEL_CLKDIV_4MHZ 6
#define MIMO_ANTSEL_BUSY 0x4000 /* bit 14 (busy) */
@@ -1259,27 +1321,36 @@ struct shm_acparams {
#define MHF5 4 /* Hostflag 5 index */
/* Flags in M_HOST_FLAGS */
-#define MHF1_ANTDIV 0x0001 /* Enable ucode antenna diversity help */
-#define MHF1_EDCF 0x0100 /* Enable EDCF access control */
+/* Enable ucode antenna diversity help */
+#define MHF1_ANTDIV 0x0001
+/* Enable EDCF access control */
+#define MHF1_EDCF 0x0100
#define MHF1_IQSWAP_WAR 0x0200
-#define MHF1_FORCEFASTCLK 0x0400 /* Disable Slow clock request, for corerev < 11 */
+/* Disable Slow clock request, for corerev < 11 */
+#define MHF1_FORCEFASTCLK 0x0400
/* Flags in M_HOST_FLAGS2 */
-#define MHF2_PCISLOWCLKWAR 0x0008 /* PR16165WAR : Enable ucode PCI slow clock WAR */
-#define MHF2_TXBCMC_NOW 0x0040 /* Flush BCMC FIFO immediately */
-#define MHF2_HWPWRCTL 0x0080 /* Enable ucode/hw power control */
+
+/* Flush BCMC FIFO immediately */
+#define MHF2_TXBCMC_NOW 0x0040
+/* Enable ucode/hw power control */
+#define MHF2_HWPWRCTL 0x0080
#define MHF2_NPHY40MHZ_WAR 0x0800
/* Flags in M_HOST_FLAGS3 */
-#define MHF3_ANTSEL_EN 0x0001 /* enabled mimo antenna selection */
-#define MHF3_ANTSEL_MODE 0x0002 /* antenna selection mode: 0: 2x3, 1: 2x4 */
+/* enabled mimo antenna selection */
+#define MHF3_ANTSEL_EN 0x0001
+/* antenna selection mode: 0: 2x3, 1: 2x4 */
+#define MHF3_ANTSEL_MODE 0x0002
#define MHF3_RESERVED1 0x0004
#define MHF3_RESERVED2 0x0008
#define MHF3_NPHY_MLADV_WAR 0x0010
/* Flags in M_HOST_FLAGS4 */
-#define MHF4_BPHY_TXCORE0 0x0080 /* force bphy Tx on core 0 (board level WAR) */
-#define MHF4_EXTPA_ENABLE 0x4000 /* for 4313A0 FEM boards */
+/* force bphy Tx on core 0 (board level WAR) */
+#define MHF4_BPHY_TXCORE0 0x0080
+/* for 4313A0 FEM boards */
+#define MHF4_EXTPA_ENABLE 0x4000
/* Flags in M_HOST_FLAGS5 */
#define MHF5_4313_GPIOCTRL 0x0001
@@ -1292,52 +1363,80 @@ struct shm_acparams {
#define M_PHY_NOISE (0x037 * 2)
#define PHY_NOISE_MASK 0x00ff
-/* Receive Frame Data Header for 802.11b DCF-only frames */
-struct d11rxhdr {
- u16 RxFrameSize; /* Actual byte length of the frame data received */
+/*
+ * Receive Frame Data Header for 802.11b DCF-only frames
+ *
+ * RxFrameSize: Actual byte length of the frame data received
+ * PAD: padding (not used)
+ * PhyRxStatus_0: PhyRxStatus 15:0
+ * PhyRxStatus_1: PhyRxStatus 31:16
+ * PhyRxStatus_2: PhyRxStatus 47:32
+ * PhyRxStatus_3: PhyRxStatus 63:48
+ * PhyRxStatus_4: PhyRxStatus 79:64
+ * PhyRxStatus_5: PhyRxStatus 95:80
+ * RxStatus1: MAC Rx Status
+ * RxStatus2: extended MAC Rx status
+ * RxTSFTime: RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY
+ * RxChan: gain code, channel radio code, and phy type
+ */
+struct d11rxhdr_le {
+ __le16 RxFrameSize;
u16 PAD;
- u16 PhyRxStatus_0; /* PhyRxStatus 15:0 */
- u16 PhyRxStatus_1; /* PhyRxStatus 31:16 */
- u16 PhyRxStatus_2; /* PhyRxStatus 47:32 */
- u16 PhyRxStatus_3; /* PhyRxStatus 63:48 */
- u16 PhyRxStatus_4; /* PhyRxStatus 79:64 */
- u16 PhyRxStatus_5; /* PhyRxStatus 95:80 */
- u16 RxStatus1; /* MAC Rx Status */
- u16 RxStatus2; /* extended MAC Rx status */
- u16 RxTSFTime; /* RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY */
- u16 RxChan; /* gain code, channel radio code, and phy type */
+ __le16 PhyRxStatus_0;
+ __le16 PhyRxStatus_1;
+ __le16 PhyRxStatus_2;
+ __le16 PhyRxStatus_3;
+ __le16 PhyRxStatus_4;
+ __le16 PhyRxStatus_5;
+ __le16 RxStatus1;
+ __le16 RxStatus2;
+ __le16 RxTSFTime;
+ __le16 RxChan;
} __packed;
-#define RXHDR_LEN 24 /* sizeof struct d11rxhdr */
-#define FRAMELEN(h) ((h)->RxFrameSize)
-
-struct brcms_d11rxhdr {
- struct d11rxhdr rxhdr;
- u32 tsf_l; /* TSF_L reading */
- s8 rssi; /* computed instanteneous rssi in BMAC */
- s8 rxpwr0; /* obsoleted, place holder for legacy ROM code. use rxpwr[] */
- s8 rxpwr1; /* obsoleted, place holder for legacy ROM code. use rxpwr[] */
- s8 do_rssi_ma; /* do per-pkt sampling for per-antenna ma in HIGH */
- s8 rxpwr[WL_RSSI_ANT_MAX]; /* rssi for supported antennas */
+struct d11rxhdr {
+ u16 RxFrameSize;
+ u16 PAD;
+ u16 PhyRxStatus_0;
+ u16 PhyRxStatus_1;
+ u16 PhyRxStatus_2;
+ u16 PhyRxStatus_3;
+ u16 PhyRxStatus_4;
+ u16 PhyRxStatus_5;
+ u16 RxStatus1;
+ u16 RxStatus2;
+ u16 RxTSFTime;
+ u16 RxChan;
} __packed;
/* PhyRxStatus_0: */
-#define PRXS0_FT_MASK 0x0003 /* NPHY only: CCK, OFDM, preN, N */
-#define PRXS0_CLIP_MASK 0x000C /* NPHY only: clip count adjustment steps by AGC */
+/* NPHY only: CCK, OFDM, preN, N */
+#define PRXS0_FT_MASK 0x0003
+/* NPHY only: clip count adjustment steps by AGC */
+#define PRXS0_CLIP_MASK 0x000C
#define PRXS0_CLIP_SHIFT 2
-#define PRXS0_UNSRATE 0x0010 /* PHY received a frame with unsupported rate */
-#define PRXS0_RXANT_UPSUBBAND 0x0020 /* GPHY: rx ant, NPHY: upper sideband */
-#define PRXS0_LCRS 0x0040 /* CCK frame only: lost crs during cck frame reception */
-#define PRXS0_SHORTH 0x0080 /* Short Preamble */
-#define PRXS0_PLCPFV 0x0100 /* PLCP violation */
-#define PRXS0_PLCPHCF 0x0200 /* PLCP header integrity check failed */
-#define PRXS0_GAIN_CTL 0x4000 /* legacy PHY gain control */
-#define PRXS0_ANTSEL_MASK 0xF000 /* NPHY: Antennas used for received frame, bitmask */
+/* PHY received a frame with unsupported rate */
+#define PRXS0_UNSRATE 0x0010
+/* GPHY: rx ant, NPHY: upper sideband */
+#define PRXS0_RXANT_UPSUBBAND 0x0020
+/* CCK frame only: lost crs during cck frame reception */
+#define PRXS0_LCRS 0x0040
+/* Short Preamble */
+#define PRXS0_SHORTH 0x0080
+/* PLCP violation */
+#define PRXS0_PLCPFV 0x0100
+/* PLCP header integrity check failed */
+#define PRXS0_PLCPHCF 0x0200
+/* legacy PHY gain control */
+#define PRXS0_GAIN_CTL 0x4000
+/* NPHY: Antennas used for received frame, bitmask */
+#define PRXS0_ANTSEL_MASK 0xF000
#define PRXS0_ANTSEL_SHIFT 0x12
/* subfield PRXS0_FT_MASK */
#define PRXS0_CCK 0x0000
-#define PRXS0_OFDM 0x0001 /* valid only for G phy, use rxh->RxChan for A phy */
+/* valid only for G phy, use rxh->RxChan for A phy */
+#define PRXS0_OFDM 0x0001
#define PRXS0_PREN 0x0002
#define PRXS0_STDN 0x0003
@@ -1364,35 +1463,51 @@ struct brcms_d11rxhdr {
#define PRXS0_UNUSED 0xF000 /* unused and not defined; set to 0 */
/* htphy PhyRxStatus_1: */
-#define PRXS1_HTPHY_CORE_MASK 0x000F /* core enables for {3..0}, 0=disabled, 1=enabled */
-#define PRXS1_HTPHY_ANTCFG_MASK 0x00F0 /* antenna configation */
-#define PRXS1_HTPHY_MMPLCPLenL_MASK 0xFF00 /* Mixmode PLCP Length low byte mask */
+/* core enables for {3..0}, 0=disabled, 1=enabled */
+#define PRXS1_HTPHY_CORE_MASK 0x000F
+/* antenna configation */
+#define PRXS1_HTPHY_ANTCFG_MASK 0x00F0
+/* Mixmode PLCP Length low byte mask */
+#define PRXS1_HTPHY_MMPLCPLenL_MASK 0xFF00
/* htphy PhyRxStatus_2: */
-#define PRXS2_HTPHY_MMPLCPLenH_MASK 0x000F /* Mixmode PLCP Length high byte maskw */
-#define PRXS2_HTPHY_MMPLCH_RATE_MASK 0x00F0 /* Mixmode PLCP rate mask */
-#define PRXS2_HTPHY_RXPWR_ANT0 0xFF00 /* Rx power on core 0 */
+/* Mixmode PLCP Length high byte maskw */
+#define PRXS2_HTPHY_MMPLCPLenH_MASK 0x000F
+/* Mixmode PLCP rate mask */
+#define PRXS2_HTPHY_MMPLCH_RATE_MASK 0x00F0
+/* Rx power on core 0 */
+#define PRXS2_HTPHY_RXPWR_ANT0 0xFF00
/* htphy PhyRxStatus_3: */
-#define PRXS3_HTPHY_RXPWR_ANT1 0x00FF /* Rx power on core 1 */
-#define PRXS3_HTPHY_RXPWR_ANT2 0xFF00 /* Rx power on core 2 */
+/* Rx power on core 1 */
+#define PRXS3_HTPHY_RXPWR_ANT1 0x00FF
+/* Rx power on core 2 */
+#define PRXS3_HTPHY_RXPWR_ANT2 0xFF00
/* htphy PhyRxStatus_4: */
-#define PRXS4_HTPHY_RXPWR_ANT3 0x00FF /* Rx power on core 3 */
-#define PRXS4_HTPHY_CFO 0xFF00 /* Coarse frequency offset */
+/* Rx power on core 3 */
+#define PRXS4_HTPHY_RXPWR_ANT3 0x00FF
+/* Coarse frequency offset */
+#define PRXS4_HTPHY_CFO 0xFF00
/* htphy PhyRxStatus_5: */
-#define PRXS5_HTPHY_FFO 0x00FF /* Fine frequency offset */
-#define PRXS5_HTPHY_AR 0xFF00 /* Advance Retard */
+/* Fine frequency offset */
+#define PRXS5_HTPHY_FFO 0x00FF
+/* Advance Retard */
+#define PRXS5_HTPHY_AR 0xFF00
-#define HTPHY_MMPLCPLen(rxs) ((((rxs)->PhyRxStatus_1 & PRXS1_HTPHY_MMPLCPLenL_MASK) >> 8) | \
+#define HTPHY_MMPLCPLen(rxs) \
+ ((((rxs)->PhyRxStatus_1 & PRXS1_HTPHY_MMPLCPLenL_MASK) >> 8) | \
(((rxs)->PhyRxStatus_2 & PRXS2_HTPHY_MMPLCPLenH_MASK) << 8))
/* Get Rx power on core 0 */
-#define HTPHY_RXPWR_ANT0(rxs) ((((rxs)->PhyRxStatus_2) & PRXS2_HTPHY_RXPWR_ANT0) >> 8)
+#define HTPHY_RXPWR_ANT0(rxs) \
+ ((((rxs)->PhyRxStatus_2) & PRXS2_HTPHY_RXPWR_ANT0) >> 8)
/* Get Rx power on core 1 */
-#define HTPHY_RXPWR_ANT1(rxs) (((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT1)
+#define HTPHY_RXPWR_ANT1(rxs) \
+ (((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT1)
/* Get Rx power on core 2 */
-#define HTPHY_RXPWR_ANT2(rxs) ((((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT2) >> 8)
+#define HTPHY_RXPWR_ANT2(rxs) \
+ ((((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT2) >> 8)
/* ucode RxStatus1: */
#define RXS_BCNSENT 0x8000
@@ -1400,7 +1515,8 @@ struct brcms_d11rxhdr {
#define RXS_SECKINDX_SHIFT 5
#define RXS_DECERR (1 << 4)
#define RXS_DECATMPT (1 << 3)
-#define RXS_PBPRES (1 << 2) /* PAD bytes to make IP data 4 bytes aligned */
+/* PAD bytes to make IP data 4 bytes aligned */
+#define RXS_PBPRES (1 << 2)
#define RXS_RESPFRAMETX (1 << 1)
#define RXS_FCSERR (1 << 0)
@@ -1433,16 +1549,17 @@ struct brcms_d11rxhdr {
#define M_PSM_SOFT_REGS 0x0
#define M_BOM_REV_MAJOR (M_PSM_SOFT_REGS + 0x0)
#define M_BOM_REV_MINOR (M_PSM_SOFT_REGS + 0x2)
-#define M_UCODE_DBGST (M_PSM_SOFT_REGS + 0x40) /* ucode debug status code */
-#define M_UCODE_MACSTAT (M_PSM_SOFT_REGS + 0xE0) /* macstat counters */
+#define M_UCODE_DBGST (M_PSM_SOFT_REGS + 0x40) /* ucode debug status code */
+#define M_UCODE_MACSTAT (M_PSM_SOFT_REGS + 0xE0) /* macstat counters */
-#define M_AGING_THRSH (0x3e * 2) /* max time waiting for medium before tx */
-#define M_MBURST_SIZE (0x40 * 2) /* max frames in a frameburst */
-#define M_MBURST_TXOP (0x41 * 2) /* max frameburst TXOP in unit of us */
-#define M_SYNTHPU_DLY (0x4a * 2) /* pre-wakeup for synthpu, default: 500 */
+#define M_AGING_THRSH (0x3e * 2) /* max time waiting for medium before tx */
+#define M_MBURST_SIZE (0x40 * 2) /* max frames in a frameburst */
+#define M_MBURST_TXOP (0x41 * 2) /* max frameburst TXOP in unit of us */
+#define M_SYNTHPU_DLY (0x4a * 2) /* pre-wakeup for synthpu, default: 500 */
#define M_PRETBTT (0x4b * 2)
-#define M_ALT_TXPWR_IDX (M_PSM_SOFT_REGS + (0x3b * 2)) /* offset to the target txpwr */
+/* offset to the target txpwr */
+#define M_ALT_TXPWR_IDX (M_PSM_SOFT_REGS + (0x3b * 2))
#define M_PHY_TX_FLT_PTR (M_PSM_SOFT_REGS + (0x3d * 2))
#define M_CTS_DURATION (M_PSM_SOFT_REGS + (0x5c * 2))
#define M_LP_RCCAL_OVR (M_PSM_SOFT_REGS + (0x6b * 2))
@@ -1451,11 +1568,16 @@ struct brcms_d11rxhdr {
#define M_RXSTATS_BLK_PTR (M_PSM_SOFT_REGS + (0x65 * 2))
/* ucode debug status codes */
-#define DBGST_INACTIVE 0 /* not valid really */
-#define DBGST_INIT 1 /* after zeroing SHM, before suspending at init */
-#define DBGST_ACTIVE 2 /* "normal" state */
-#define DBGST_SUSPENDED 3 /* suspended */
-#define DBGST_ASLEEP 4 /* asleep (PS mode) */
+/* not valid really */
+#define DBGST_INACTIVE 0
+/* after zeroing SHM, before suspending at init */
+#define DBGST_INIT 1
+/* "normal" state */
+#define DBGST_ACTIVE 2
+/* suspended */
+#define DBGST_SUSPENDED 3
+/* asleep (PS mode) */
+#define DBGST_ASLEEP 4
/* Scratch Reg defs */
enum _ePsmScratchPadRegDefinitions {
@@ -1463,66 +1585,66 @@ enum _ePsmScratchPadRegDefinitions {
S_RSV1,
S_RSV2,
- /* scratch registers for Dot11-contants */
- S_DOT11_CWMIN, /* CW-minimum 0x03 */
- S_DOT11_CWMAX, /* CW-maximum 0x04 */
- S_DOT11_CWCUR, /* CW-current 0x05 */
- S_DOT11_SRC_LMT, /* short retry count limit 0x06 */
- S_DOT11_LRC_LMT, /* long retry count limit 0x07 */
- S_DOT11_DTIMCOUNT, /* DTIM-count 0x08 */
-
- /* Tx-side scratch registers */
- S_SEQ_NUM, /* hardware sequence number reg 0x09 */
- S_SEQ_NUM_FRAG, /* seq-num for frags (Set at the start os MSDU 0x0A */
- S_FRMRETX_CNT, /* frame retx count 0x0B */
- S_SSRC, /* Station short retry count 0x0C */
- S_SLRC, /* Station long retry count 0x0D */
- S_EXP_RSP, /* Expected response frame 0x0E */
- S_OLD_BREM, /* Remaining backoff ctr 0x0F */
- S_OLD_CWWIN, /* saved-off CW-cur 0x10 */
- S_TXECTL, /* TXE-Ctl word constructed in scr-pad 0x11 */
- S_CTXTST, /* frm type-subtype as read from Tx-descr 0x12 */
-
- /* Rx-side scratch registers */
- S_RXTST, /* Type and subtype in Rxframe 0x13 */
+ /* offset 0x03: scratch registers for Dot11-contants */
+ S_DOT11_CWMIN, /* CW-minimum */
+ S_DOT11_CWMAX, /* CW-maximum */
+ S_DOT11_CWCUR, /* CW-current */
+ S_DOT11_SRC_LMT, /* short retry count limit */
+ S_DOT11_LRC_LMT, /* long retry count limit */
+ S_DOT11_DTIMCOUNT, /* DTIM-count */
+
+ /* offset 0x09: Tx-side scratch registers */
+ S_SEQ_NUM, /* hardware sequence number reg */
+ S_SEQ_NUM_FRAG, /* seq num for frags (at the start of MSDU) */
+ S_FRMRETX_CNT, /* frame retx count */
+ S_SSRC, /* Station short retry count */
+ S_SLRC, /* Station long retry count */
+ S_EXP_RSP, /* Expected response frame */
+ S_OLD_BREM, /* Remaining backoff ctr */
+ S_OLD_CWWIN, /* saved-off CW-cur */
+ S_TXECTL, /* TXE-Ctl word constructed in scr-pad */
+ S_CTXTST, /* frm type-subtype as read from Tx-descr */
+
+ /* offset 0x13: Rx-side scratch registers */
+ S_RXTST, /* Type and subtype in Rxframe */
/* Global state register */
- S_STREG, /* state storage actual bit maps below 0x14 */
-
- S_TXPWR_SUM, /* Tx power control: accumulator 0x15 */
- S_TXPWR_ITER, /* Tx power control: iteration 0x16 */
- S_RX_FRMTYPE, /* Rate and PHY type for frames 0x17 */
- S_THIS_AGG, /* Size of this AGG (A-MSDU) 0x18 */
-
- S_KEYINDX, /* 0x19 */
- S_RXFRMLEN, /* Receive MPDU length in bytes 0x1A */
-
- /* Receive TSF time stored in SCR */
- S_RXTSFTMRVAL_WD3, /* TSF value at the start of rx 0x1B */
- S_RXTSFTMRVAL_WD2, /* TSF value at the start of rx 0x1C */
- S_RXTSFTMRVAL_WD1, /* TSF value at the start of rx 0x1D */
- S_RXTSFTMRVAL_WD0, /* TSF value at the start of rx 0x1E */
- S_RXSSN, /* Received start seq number for A-MPDU BA 0x1F */
- S_RXQOSFLD, /* Rx-QoS field (if present) 0x20 */
-
- /* Scratch pad regs used in microcode as temp storage */
- S_TMP0, /* stmp0 0x21 */
- S_TMP1, /* stmp1 0x22 */
- S_TMP2, /* stmp2 0x23 */
- S_TMP3, /* stmp3 0x24 */
- S_TMP4, /* stmp4 0x25 */
- S_TMP5, /* stmp5 0x26 */
- S_PRQPENALTY_CTR, /* Probe response queue penalty counter 0x27 */
- S_ANTCNT, /* unsuccessful attempts on current ant. 0x28 */
- S_SYMBOL, /* flag for possible symbol ctl frames 0x29 */
- S_RXTP, /* rx frame type 0x2A */
- S_STREG2, /* extra state storage 0x2B */
- S_STREG3, /* even more extra state storage 0x2C */
- S_STREG4, /* ... 0x2D */
- S_STREG5, /* remember to initialize it to zero 0x2E */
+ S_STREG, /* state storage actual bit maps below */
+
+ S_TXPWR_SUM, /* Tx power control: accumulator */
+ S_TXPWR_ITER, /* Tx power control: iteration */
+ S_RX_FRMTYPE, /* Rate and PHY type for frames */
+ S_THIS_AGG, /* Size of this AGG (A-MSDU) */
+
+ S_KEYINDX,
+ S_RXFRMLEN, /* Receive MPDU length in bytes */
+
+ /* offset 0x1B: Receive TSF time stored in SCR */
+ S_RXTSFTMRVAL_WD3, /* TSF value at the start of rx */
+ S_RXTSFTMRVAL_WD2, /* TSF value at the start of rx */
+ S_RXTSFTMRVAL_WD1, /* TSF value at the start of rx */
+ S_RXTSFTMRVAL_WD0, /* TSF value at the start of rx */
+ S_RXSSN, /* Received start seq number for A-MPDU BA */
+ S_RXQOSFLD, /* Rx-QoS field (if present) */
+
+ /* offset 0x21: Scratch pad regs used in microcode as temp storage */
+ S_TMP0, /* stmp0 */
+ S_TMP1, /* stmp1 */
+ S_TMP2, /* stmp2 */
+ S_TMP3, /* stmp3 */
+ S_TMP4, /* stmp4 */
+ S_TMP5, /* stmp5 */
+ S_PRQPENALTY_CTR, /* Probe response queue penalty counter */
+ S_ANTCNT, /* unsuccessful attempts on current ant. */
+ S_SYMBOL, /* flag for possible symbol ctl frames */
+ S_RXTP, /* rx frame type */
+ S_STREG2, /* extra state storage */
+ S_STREG3, /* even more extra state storage */
+ S_STREG4, /* ... */
+ S_STREG5, /* remember to initialize it to zero */
S_ADJPWR_IDX,
- S_CUR_PTR, /* Temp pointer for A-MPDU re-Tx SHM table 0x32 */
+ S_CUR_PTR, /* Temp pointer for A-MPDU re-Tx SHM table */
S_REVID4, /* 0x33 */
S_INDX, /* 0x34 */
S_ADDR0, /* 0x35 */
@@ -1532,9 +1654,9 @@ enum _ePsmScratchPadRegDefinitions {
S_ADDR4, /* 0x39 */
S_ADDR5, /* 0x3A */
S_TMP6, /* 0x3B */
- S_KEYINDX_BU, /* Backup for Key index 0x3C */
- S_MFGTEST_TMP0, /* Temp register used for RX test calculations 0x3D */
- S_RXESN, /* Received end sequence number for A-MPDU BA 0x3E */
+ S_KEYINDX_BU, /* Backup for Key index */
+ S_MFGTEST_TMP0, /* Temp regs used for RX test calculations */
+ S_RXESN, /* Received end sequence number for A-MPDU BA */
S_STREG6, /* 0x3F */
};
@@ -1628,7 +1750,8 @@ struct macstat {
#define SISF_FCLKA 0x0004 /* FastClkAvailable */
#define SISF_DB_PHY 0x0008 /* Dualband phy */
-/* === End of MAC reg, Beginning of PHY(b/a/g/n) reg, radio and LPPHY regs are separated === */
+/* === End of MAC reg, Beginning of PHY(b/a/g/n) reg === */
+/* radio and LPPHY regs are separated */
#define BPHY_REG_OFT_BASE 0x0
/* offsets for indirect access to bphy registers */
diff --git a/drivers/staging/brcm80211/brcmsmac/dma.c b/drivers/staging/brcm80211/brcmsmac/dma.c
index ea17671efb63..b56a30297c26 100644
--- a/drivers/staging/brcm80211/brcmsmac/dma.c
+++ b/drivers/staging/brcm80211/brcmsmac/dma.c
@@ -18,17 +18,14 @@
#include <linux/delay.h>
#include <linux/pci.h>
-#if defined(__mips__)
-#include <asm/addrspace.h>
-#endif
-
#include <brcmu_utils.h>
#include <aiutils.h>
#include "types.h"
#include "dma.h"
/*
- * Each descriptor ring must be 8kB aligned, and fit within a contiguous 8kB physical address.
+ * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
+ * a contiguous 8kB physical address.
*/
#define D64RINGALIGN_BITS 13
#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS)
@@ -69,21 +66,32 @@
#define D64_XS1_XE_COREE 0x50000000 /* core error */
/* receive channel control */
-#define D64_RC_RE 0x00000001 /* receive enable */
-#define D64_RC_RO_MASK 0x000000fe /* receive frame offset */
+/* receive enable */
+#define D64_RC_RE 0x00000001
+/* receive frame offset */
+#define D64_RC_RO_MASK 0x000000fe
#define D64_RC_RO_SHIFT 1
-#define D64_RC_FM 0x00000100 /* direct fifo receive (pio) mode */
-#define D64_RC_SH 0x00000200 /* separate rx header descriptor enable */
-#define D64_RC_OC 0x00000400 /* overflow continue */
-#define D64_RC_PD 0x00000800 /* parity check disable */
-#define D64_RC_AE 0x00030000 /* address extension bits */
+/* direct fifo receive (pio) mode */
+#define D64_RC_FM 0x00000100
+/* separate rx header descriptor enable */
+#define D64_RC_SH 0x00000200
+/* overflow continue */
+#define D64_RC_OC 0x00000400
+/* parity check disable */
+#define D64_RC_PD 0x00000800
+/* address extension bits */
+#define D64_RC_AE 0x00030000
#define D64_RC_AE_SHIFT 16
/* flags for dma controller */
-#define DMA_CTRL_PEN (1 << 0) /* partity enable */
-#define DMA_CTRL_ROC (1 << 1) /* rx overflow continue */
-#define DMA_CTRL_RXMULTI (1 << 2) /* allow rx scatter to multiple descriptors */
-#define DMA_CTRL_UNFRAMED (1 << 3) /* Unframed Rx/Tx data */
+/* partity enable */
+#define DMA_CTRL_PEN (1 << 0)
+/* rx overflow continue */
+#define DMA_CTRL_ROC (1 << 1)
+/* allow rx scatter to multiple descriptors */
+#define DMA_CTRL_RXMULTI (1 << 2)
+/* Unframed Rx/Tx data */
+#define DMA_CTRL_UNFRAMED (1 << 3)
/* receive descriptor table pointer */
#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */
@@ -131,10 +139,13 @@
#define D64_CTRL1_SOF ((u32)1 << 31) /* start of frame */
/* descriptor control flags 2 */
-#define D64_CTRL2_BC_MASK 0x00007fff /* buffer byte count. real data len must <= 16KB */
-#define D64_CTRL2_AE 0x00030000 /* address extension bits */
+/* buffer byte count. real data len must <= 16KB */
+#define D64_CTRL2_BC_MASK 0x00007fff
+/* address extension bits */
+#define D64_CTRL2_AE 0x00030000
#define D64_CTRL2_AE_SHIFT 16
-#define D64_CTRL2_PARITY 0x00040000 /* parity bit */
+/* parity bit */
+#define D64_CTRL2_PARITY 0x00040000
/* control flags in the range [27:20] are core-specific and not defined here */
#define D64_CTRL_CORE_MASK 0x0ff00000
@@ -144,15 +155,13 @@
#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1 */
#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */
-#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */
-#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */
-#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */
-#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */
-
-/* packet headroom necessary to accommodate the largest header in the system, (i.e TXOFF).
- * By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL.
- * There is a compile time check in wlc.c which ensure that this value is at least as big
- * as TXOFF. This value is used in dma_rxfill (dma.c).
+/*
+ * packet headroom necessary to accommodate the largest header
+ * in the system, (i.e TXOFF). By doing, we avoid the need to
+ * allocate an extra buffer for the header when bridging to WL.
+ * There is a compile time check in wlc.c which ensure that this
+ * value is at least as big as TXOFF. This value is used in
+ * dma_rxfill().
*/
#define BCMEXTRAHDROOM 172
@@ -180,52 +189,27 @@
#define DMA_NONE(args)
-typedef unsigned long dmaaddr_t;
-#define PHYSADDRHI(_pa) (0)
-#define PHYSADDRHISET(_pa, _val)
-#define PHYSADDRLO(_pa) ((_pa))
-#define PHYSADDRLOSET(_pa, _val) \
- do { \
- (_pa) = (_val); \
- } while (0)
-
-#define d64txregs dregs.d64_u.txregs_64
-#define d64rxregs dregs.d64_u.rxregs_64
-#define txd64 dregs.d64_u.txd_64
-#define rxd64 dregs.d64_u.rxd_64
-
-/* default dma message level (if input msg_level pointer is null in dma_attach()) */
-static uint dma_msg_level;
-
#define MAXNAMEL 8 /* 8 char names */
-#define DI_INFO(dmah) ((dma_info_t *)dmah)
-
-#define R_SM(r) (*(r))
-#define W_SM(r, v) (*(r) = (v))
+/* macros to convert between byte offsets and indexes */
+#define B2I(bytes, type) ((bytes) / sizeof(type))
+#define I2B(index, type) ((index) * sizeof(type))
-/* One physical DMA segment */
-struct dma_seg {
- dmaaddr_t addr;
- u32 length;
-};
+#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
+#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */
-struct dma_seg_map {
- void *oshdmah; /* Opaque handle for OSL to store its information */
- uint origsize; /* Size of the virtual packet */
- uint nsegs;
- struct dma_seg segs[MAX_DMA_SEGS];
-};
+#define PCI64ADDR_HIGH 0x80000000 /* address[63] */
+#define PCI64ADDR_HIGH_SHIFT 31 /* address[63] */
/*
* DMA Descriptor
* Descriptors are only read by the hardware, never written back.
*/
struct dma64desc {
- u32 ctrl1; /* misc control bits & bufcount */
- u32 ctrl2; /* buffer count and address extension */
- u32 addrlow; /* memory address of the date buffer, bits 31:0 */
- u32 addrhigh; /* memory address of the date buffer, bits 63:32 */
+ __le32 ctrl1; /* misc control bits & bufcount */
+ __le32 ctrl2; /* buffer count and address extension */
+ __le32 addrlow; /* memory address of the date buffer, bits 31:0 */
+ __le32 addrhigh; /* memory address of the date buffer, bits 63:32 */
};
/* dma engine software state */
@@ -234,208 +218,344 @@ struct dma_info {
uint *msg_level; /* message level pointer */
char name[MAXNAMEL]; /* callers name for diag msgs */
- void *pbus; /* bus handle */
+ struct pci_dev *pbus; /* bus handle */
- bool dma64; /* this dma engine is operating in 64-bit mode */
- bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
+ bool dma64; /* this dma engine is operating in 64-bit mode */
+ bool addrext; /* this dma engine supports DmaExtendedAddrChanges */
- union {
- struct {
- dma64regs_t *txregs_64; /* 64-bit dma tx engine registers */
- dma64regs_t *rxregs_64; /* 64-bit dma rx engine registers */
- /* pointer to dma64 tx descriptor ring */
- struct dma64desc *txd_64;
- /* pointer to dma64 rx descriptor ring */
- struct dma64desc *rxd_64;
- } d64_u;
- } dregs;
+ /* 64-bit dma tx engine registers */
+ struct dma64regs __iomem *d64txregs;
+ /* 64-bit dma rx engine registers */
+ struct dma64regs __iomem *d64rxregs;
+ /* pointer to dma64 tx descriptor ring */
+ struct dma64desc *txd64;
+ /* pointer to dma64 rx descriptor ring */
+ struct dma64desc *rxd64;
u16 dmadesc_align; /* alignment requirement for dma descriptors */
u16 ntxd; /* # tx descriptors tunable */
u16 txin; /* index of next descriptor to reclaim */
u16 txout; /* index of next descriptor to post */
- void **txp; /* pointer to parallel array of pointers to packets */
- struct dma_seg_map *txp_dmah; /* DMA MAP meta-data handle */
- dmaaddr_t txdpa; /* Aligned physical address of descriptor ring */
- dmaaddr_t txdpaorig; /* Original physical address of descriptor ring */
+ /* pointer to parallel array of pointers to packets */
+ struct sk_buff **txp;
+ /* Aligned physical address of descriptor ring */
+ dma_addr_t txdpa;
+ /* Original physical address of descriptor ring */
+ dma_addr_t txdpaorig;
u16 txdalign; /* #bytes added to alloc'd mem to align txd */
u32 txdalloc; /* #bytes allocated for the ring */
u32 xmtptrbase; /* When using unaligned descriptors, the ptr register
- * is not just an index, it needs all 13 bits to be
- * an offset from the addr register.
- */
+ * is not just an index, it needs all 13 bits to be
+ * an offset from the addr register.
+ */
- u16 nrxd; /* # rx descriptors tunable */
- u16 rxin; /* index of next descriptor to reclaim */
- u16 rxout; /* index of next descriptor to post */
- void **rxp; /* pointer to parallel array of pointers to packets */
- struct dma_seg_map *rxp_dmah; /* DMA MAP meta-data handle */
- dmaaddr_t rxdpa; /* Aligned physical address of descriptor ring */
- dmaaddr_t rxdpaorig; /* Original physical address of descriptor ring */
+ u16 nrxd; /* # rx descriptors tunable */
+ u16 rxin; /* index of next descriptor to reclaim */
+ u16 rxout; /* index of next descriptor to post */
+ /* pointer to parallel array of pointers to packets */
+ struct sk_buff **rxp;
+ /* Aligned physical address of descriptor ring */
+ dma_addr_t rxdpa;
+ /* Original physical address of descriptor ring */
+ dma_addr_t rxdpaorig;
u16 rxdalign; /* #bytes added to alloc'd mem to align rxd */
u32 rxdalloc; /* #bytes allocated for the ring */
u32 rcvptrbase; /* Base for ptr reg when using unaligned descriptors */
/* tunables */
- unsigned int rxbufsize; /* rx buffer size in bytes,
- * not including the extra headroom
+ unsigned int rxbufsize; /* rx buffer size in bytes, not including
+ * the extra headroom
*/
- uint rxextrahdrroom; /* extra rx headroom, reverseved to assist upper stack
- * e.g. some rx pkt buffers will be bridged to tx side
- * without byte copying. The extra headroom needs to be
- * large enough to fit txheader needs.
- * Some dongle driver may not need it.
+ uint rxextrahdrroom; /* extra rx headroom, reverseved to assist upper
+ * stack, e.g. some rx pkt buffers will be
+ * bridged to tx side without byte copying.
+ * The extra headroom needs to be large enough
+ * to fit txheader needs. Some dongle driver may
+ * not need it.
*/
uint nrxpost; /* # rx buffers to keep posted */
unsigned int rxoffset; /* rxcontrol offset */
- uint ddoffsetlow; /* add to get dma address of descriptor ring, low 32 bits */
- uint ddoffsethigh; /* high 32 bits */
- uint dataoffsetlow; /* add to get dma address of data buffer, low 32 bits */
- uint dataoffsethigh; /* high 32 bits */
- bool aligndesc_4k; /* descriptor base need to be aligned or not */
+ /* add to get dma address of descriptor ring, low 32 bits */
+ uint ddoffsetlow;
+ /* high 32 bits */
+ uint ddoffsethigh;
+ /* add to get dma address of data buffer, low 32 bits */
+ uint dataoffsetlow;
+ /* high 32 bits */
+ uint dataoffsethigh;
+ /* descriptor base need to be aligned or not */
+ bool aligndesc_4k;
};
-/* DMA Scatter-gather list is supported. Note this is limited to TX direction only */
-#ifdef BCMDMASGLISTOSL
-#define DMASGLIST_ENAB true
-#else
-#define DMASGLIST_ENAB false
-#endif /* BCMDMASGLISTOSL */
+/*
+ * default dma message level (if input msg_level
+ * pointer is null in dma_attach())
+ */
+static uint dma_msg_level;
-/* descriptor bumping macros */
-#define XXD(x, n) ((x) & ((n) - 1)) /* faster than %, but n must be power of 2 */
-#define TXD(x) XXD((x), di->ntxd)
-#define RXD(x) XXD((x), di->nrxd)
-#define NEXTTXD(i) TXD((i) + 1)
-#define PREVTXD(i) TXD((i) - 1)
-#define NEXTRXD(i) RXD((i) + 1)
-#define PREVRXD(i) RXD((i) - 1)
+/* Check for odd number of 1's */
+static u32 parity32(__le32 data)
+{
+ /* no swap needed for counting 1's */
+ u32 par_data = *(u32 *)&data;
-#define NTXDACTIVE(h, t) TXD((t) - (h))
-#define NRXDACTIVE(h, t) RXD((t) - (h))
+ par_data ^= par_data >> 16;
+ par_data ^= par_data >> 8;
+ par_data ^= par_data >> 4;
+ par_data ^= par_data >> 2;
+ par_data ^= par_data >> 1;
-/* macros to convert between byte offsets and indexes */
-#define B2I(bytes, type) ((bytes) / sizeof(type))
-#define I2B(index, type) ((index) * sizeof(type))
+ return par_data & 1;
+}
-#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */
-#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */
+static bool dma64_dd_parity(struct dma64desc *dd)
+{
+ return parity32(dd->addrlow ^ dd->addrhigh ^ dd->ctrl1 ^ dd->ctrl2);
+}
-#define PCI64ADDR_HIGH 0x80000000 /* address[63] */
-#define PCI64ADDR_HIGH_SHIFT 31 /* address[63] */
+/* descriptor bumping functions */
+
+static uint xxd(uint x, uint n)
+{
+ return x & (n - 1); /* faster than %, but n must be power of 2 */
+}
+
+static uint txd(struct dma_info *di, uint x)
+{
+ return xxd(x, di->ntxd);
+}
+
+static uint rxd(struct dma_info *di, uint x)
+{
+ return xxd(x, di->nrxd);
+}
+
+static uint nexttxd(struct dma_info *di, uint i)
+{
+ return txd(di, i + 1);
+}
+
+static uint prevtxd(struct dma_info *di, uint i)
+{
+ return txd(di, i - 1);
+}
+
+static uint nextrxd(struct dma_info *di, uint i)
+{
+ return txd(di, i + 1);
+}
+
+static uint ntxdactive(struct dma_info *di, uint h, uint t)
+{
+ return txd(di, t-h);
+}
+
+static uint nrxdactive(struct dma_info *di, uint h, uint t)
+{
+ return rxd(di, t-h);
+}
+
+static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
+{
+ uint dmactrlflags = di->dma.dmactrlflags;
+
+ if (di == NULL) {
+ DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name));
+ return 0;
+ }
+
+ dmactrlflags &= ~mask;
+ dmactrlflags |= flags;
+
+ /* If trying to enable parity, check if parity is actually supported */
+ if (dmactrlflags & DMA_CTRL_PEN) {
+ u32 control;
+
+ control = R_REG(&di->d64txregs->control);
+ W_REG(&di->d64txregs->control,
+ control | D64_XC_PD);
+ if (R_REG(&di->d64txregs->control) & D64_XC_PD)
+ /* We *can* disable it so it is supported,
+ * restore control register
+ */
+ W_REG(&di->d64txregs->control,
+ control);
+ else
+ /* Not supported, don't allow it to be enabled */
+ dmactrlflags &= ~DMA_CTRL_PEN;
+ }
+
+ di->dma.dmactrlflags = dmactrlflags;
+
+ return dmactrlflags;
+}
+
+static bool _dma64_addrext(struct dma64regs __iomem *dma64regs)
+{
+ u32 w;
+ OR_REG(&dma64regs->control, D64_XC_AE);
+ w = R_REG(&dma64regs->control);
+ AND_REG(&dma64regs->control, ~D64_XC_AE);
+ return (w & D64_XC_AE) == D64_XC_AE;
+}
+
+/*
+ * return true if this dma engine supports DmaExtendedAddrChanges,
+ * otherwise false
+ */
+static bool _dma_isaddrext(struct dma_info *di)
+{
+ /* DMA64 supports full 32- or 64-bit operation. AE is always valid */
+
+ /* not all tx or rx channel are available */
+ if (di->d64txregs != NULL) {
+ if (!_dma64_addrext(di->d64txregs))
+ DMA_ERROR(("%s: _dma_isaddrext: DMA64 tx doesn't have "
+ "AE set\n", di->name));
+ return true;
+ } else if (di->d64rxregs != NULL) {
+ if (!_dma64_addrext(di->d64rxregs))
+ DMA_ERROR(("%s: _dma_isaddrext: DMA64 rx doesn't have "
+ "AE set\n", di->name));
+ return true;
+ }
-/* Common prototypes */
-static bool _dma_isaddrext(struct dma_info *di);
-static bool _dma_descriptor_align(struct dma_info *di);
-static bool _dma_alloc(struct dma_info *di, uint direction);
-static void _dma_detach(struct dma_info *di);
-static void _dma_ddtable_init(struct dma_info *di, uint direction,
- dmaaddr_t pa);
-static void _dma_rxinit(struct dma_info *di);
-static void *_dma_rx(struct dma_info *di);
-static bool _dma_rxfill(struct dma_info *di);
-static void _dma_rxreclaim(struct dma_info *di);
-static void _dma_rxenable(struct dma_info *di);
-static void *_dma_getnextrxp(struct dma_info *di, bool forceall);
-static void _dma_rx_param_get(struct dma_info *di, u16 *rxoffset,
- u16 *rxbufsize);
-
-static void _dma_txblock(struct dma_info *di);
-static void _dma_txunblock(struct dma_info *di);
-static uint _dma_txactive(struct dma_info *di);
-static uint _dma_rxactive(struct dma_info *di);
-static uint _dma_txpending(struct dma_info *di);
-static uint _dma_txcommitted(struct dma_info *di);
-
-static void *_dma_peeknexttxp(struct dma_info *di);
-static void *_dma_peeknextrxp(struct dma_info *di);
-static unsigned long _dma_getvar(struct dma_info *di, const char *name);
-static void _dma_counterreset(struct dma_info *di);
-static void _dma_fifoloopbackenable(struct dma_info *di);
-static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags);
-static u8 dma_align_sizetobits(uint size);
+ return false;
+}
+
+static bool _dma_descriptor_align(struct dma_info *di)
+{
+ u32 addrl;
+
+ /* Check to see if the descriptors need to be aligned on 4K/8K or not */
+ if (di->d64txregs != NULL) {
+ W_REG(&di->d64txregs->addrlow, 0xff0);
+ addrl = R_REG(&di->d64txregs->addrlow);
+ if (addrl != 0)
+ return false;
+ } else if (di->d64rxregs != NULL) {
+ W_REG(&di->d64rxregs->addrlow, 0xff0);
+ addrl = R_REG(&di->d64rxregs->addrlow);
+ if (addrl != 0)
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Descriptor table must start at the DMA hardware dictated alignment, so
+ * allocated memory must be large enough to support this requirement.
+ */
+static void *dma_alloc_consistent(struct pci_dev *pdev, uint size,
+ u16 align_bits, uint *alloced,
+ dma_addr_t *pap)
+{
+ if (align_bits) {
+ u16 align = (1 << align_bits);
+ if (!IS_ALIGNED(PAGE_SIZE, align))
+ size += align;
+ *alloced = size;
+ }
+ return pci_alloc_consistent(pdev, size, pap);
+}
+
+static
+u8 dma_align_sizetobits(uint size)
+{
+ u8 bitpos = 0;
+ while (size >>= 1)
+ bitpos++;
+ return bitpos;
+}
+
+/* This function ensures that the DMA descriptor ring will not get allocated
+ * across Page boundary. If the allocation is done across the page boundary
+ * at the first time, then it is freed and the allocation is done at
+ * descriptor ring size aligned location. This will ensure that the ring will
+ * not cross page boundary
+ */
static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
u16 *alignbits, uint *alloced,
- dmaaddr_t *descpa);
-
-/* Prototypes for 64-bit routines */
-static bool dma64_alloc(struct dma_info *di, uint direction);
-static bool dma64_txreset(struct dma_info *di);
-static bool dma64_rxreset(struct dma_info *di);
-static bool dma64_txsuspendedidle(struct dma_info *di);
-static int dma64_txfast(struct dma_info *di, struct sk_buff *p0, bool commit);
-static int dma64_txunframed(struct dma_info *di, void *p0, uint len,
- bool commit);
-static void *dma64_getpos(struct dma_info *di, bool direction);
-static void *dma64_getnexttxp(struct dma_info *di, enum txd_range range);
-static void *dma64_getnextrxp(struct dma_info *di, bool forceall);
-static void dma64_txrotate(struct dma_info *di);
-
-static bool dma64_rxidle(struct dma_info *di);
-static void dma64_txinit(struct dma_info *di);
-static bool dma64_txenabled(struct dma_info *di);
-static void dma64_txsuspend(struct dma_info *di);
-static void dma64_txresume(struct dma_info *di);
-static bool dma64_txsuspended(struct dma_info *di);
-static void dma64_txreclaim(struct dma_info *di, enum txd_range range);
-static bool dma64_txstopped(struct dma_info *di);
-static bool dma64_rxstopped(struct dma_info *di);
-static bool dma64_rxenabled(struct dma_info *di);
-static bool _dma64_addrext(dma64regs_t *dma64regs);
-
-static inline u32 parity32(u32 data);
-
-const struct di_fcn_s dma64proc = {
- (di_detach_t) _dma_detach,
- (di_txinit_t) dma64_txinit,
- (di_txreset_t) dma64_txreset,
- (di_txenabled_t) dma64_txenabled,
- (di_txsuspend_t) dma64_txsuspend,
- (di_txresume_t) dma64_txresume,
- (di_txsuspended_t) dma64_txsuspended,
- (di_txsuspendedidle_t) dma64_txsuspendedidle,
- (di_txfast_t) dma64_txfast,
- (di_txunframed_t) dma64_txunframed,
- (di_getpos_t) dma64_getpos,
- (di_txstopped_t) dma64_txstopped,
- (di_txreclaim_t) dma64_txreclaim,
- (di_getnexttxp_t) dma64_getnexttxp,
- (di_peeknexttxp_t) _dma_peeknexttxp,
- (di_txblock_t) _dma_txblock,
- (di_txunblock_t) _dma_txunblock,
- (di_txactive_t) _dma_txactive,
- (di_txrotate_t) dma64_txrotate,
-
- (di_rxinit_t) _dma_rxinit,
- (di_rxreset_t) dma64_rxreset,
- (di_rxidle_t) dma64_rxidle,
- (di_rxstopped_t) dma64_rxstopped,
- (di_rxenable_t) _dma_rxenable,
- (di_rxenabled_t) dma64_rxenabled,
- (di_rx_t) _dma_rx,
- (di_rxfill_t) _dma_rxfill,
- (di_rxreclaim_t) _dma_rxreclaim,
- (di_getnextrxp_t) _dma_getnextrxp,
- (di_peeknextrxp_t) _dma_peeknextrxp,
- (di_rxparam_get_t) _dma_rx_param_get,
-
- (di_fifoloopbackenable_t) _dma_fifoloopbackenable,
- (di_getvar_t) _dma_getvar,
- (di_counterreset_t) _dma_counterreset,
- (di_ctrlflags_t) _dma_ctrlflags,
- NULL,
- NULL,
- NULL,
- (di_rxactive_t) _dma_rxactive,
- (di_txpending_t) _dma_txpending,
- (di_txcommitted_t) _dma_txcommitted,
- 39
-};
+ dma_addr_t *descpa)
+{
+ void *va;
+ u32 desc_strtaddr;
+ u32 alignbytes = 1 << *alignbits;
+
+ va = dma_alloc_consistent(di->pbus, size, *alignbits, alloced, descpa);
+
+ if (NULL == va)
+ return NULL;
+
+ desc_strtaddr = (u32) roundup((unsigned long)va, alignbytes);
+ if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
+ & boundary)) {
+ *alignbits = dma_align_sizetobits(size);
+ pci_free_consistent(di->pbus, size, va, *descpa);
+ va = dma_alloc_consistent(di->pbus, size, *alignbits,
+ alloced, descpa);
+ }
+ return va;
+}
+
+static bool dma64_alloc(struct dma_info *di, uint direction)
+{
+ u16 size;
+ uint ddlen;
+ void *va;
+ uint alloced = 0;
+ u16 align;
+ u16 align_bits;
+
+ ddlen = sizeof(struct dma64desc);
+
+ size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
+ align_bits = di->dmadesc_align;
+ align = (1 << align_bits);
+
+ if (direction == DMA_TX) {
+ va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
+ &alloced, &di->txdpaorig);
+ if (va == NULL) {
+ DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(ntxd)"
+ " failed\n", di->name));
+ return false;
+ }
+ align = (1 << align_bits);
+ di->txd64 = (struct dma64desc *)
+ roundup((unsigned long)va, align);
+ di->txdalign = (uint) ((s8 *)di->txd64 - (s8 *) va);
+ di->txdpa = di->txdpaorig + di->txdalign;
+ di->txdalloc = alloced;
+ } else {
+ va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
+ &alloced, &di->rxdpaorig);
+ if (va == NULL) {
+ DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(nrxd)"
+ " failed\n", di->name));
+ return false;
+ }
+ align = (1 << align_bits);
+ di->rxd64 = (struct dma64desc *)
+ roundup((unsigned long)va, align);
+ di->rxdalign = (uint) ((s8 *)di->rxd64 - (s8 *) va);
+ di->rxdpa = di->rxdpaorig + di->rxdalign;
+ di->rxdalloc = alloced;
+ }
+
+ return true;
+}
+
+static bool _dma_alloc(struct dma_info *di, uint direction)
+{
+ return dma64_alloc(di, direction);
+}
struct dma_pub *dma_attach(char *name, struct si_pub *sih,
- void *dmaregstx, void *dmaregsrx, uint ntxd,
- uint nrxd, uint rxbufsize, int rxextheadroom,
+ void __iomem *dmaregstx, void __iomem *dmaregsrx,
+ uint ntxd, uint nrxd,
+ uint rxbufsize, int rxextheadroom,
uint nrxpost, uint rxoffset, uint *msg_level)
{
struct dma_info *di;
@@ -443,12 +563,8 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
/* allocate private info structure */
di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC);
- if (di == NULL) {
-#ifdef BCMDBG
- printk(KERN_ERR "dma_attach: out of memory\n");
-#endif
+ if (di == NULL)
return NULL;
- }
di->msg_level = msg_level ? msg_level : &dma_msg_level;
@@ -456,17 +572,15 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
di->dma64 = ((ai_core_sflags(sih, 0, 0) & SISF_DMA64) == SISF_DMA64);
/* init dma reg pointer */
- di->d64txregs = (dma64regs_t *) dmaregstx;
- di->d64rxregs = (dma64regs_t *) dmaregsrx;
- di->dma.di_fn = (const struct di_fcn_s *)&dma64proc;
-
- /* Default flags (which can be changed by the driver calling dma_ctrlflags
- * before enable): For backwards compatibility both Rx Overflow Continue
- * and Parity are DISABLED.
- * supports it.
+ di->d64txregs = (struct dma64regs __iomem *) dmaregstx;
+ di->d64rxregs = (struct dma64regs __iomem *) dmaregsrx;
+
+ /*
+ * Default flags (which can be changed by the driver calling
+ * dma_ctrlflags before enable): For backwards compatibility
+ * both Rx Overflow Continue and Parity are DISABLED.
*/
- di->dma.di_fn->ctrlflags(&di->dma, DMA_CTRL_ROC | DMA_CTRL_PEN,
- 0);
+ _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
DMA_TRACE(("%s: dma_attach: %s flags 0x%x ntxd %d nrxd %d "
"rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
@@ -497,23 +611,18 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
/*
* figure out the DMA physical address offset for dd and data
- * PCI/PCIE: they map silicon backplace address to zero based memory, need offset
- * Other bus: use zero
- * SI_BUS BIGENDIAN kludge: use sdram swapped region for data buffer, not descriptor
+ * PCI/PCIE: they map silicon backplace address to zero
+ * based memory, need offset
+ * Other bus: use zero SI_BUS BIGENDIAN kludge: use sdram
+ * swapped region for data buffer, not descriptor
*/
di->ddoffsetlow = 0;
di->dataoffsetlow = 0;
- /* for pci bus, add offset */
- if (sih->bustype == PCI_BUS) {
- /* pcie with DMA64 */
- di->ddoffsetlow = 0;
- di->ddoffsethigh = SI_PCIE_DMA_H32;
- di->dataoffsetlow = di->ddoffsetlow;
- di->dataoffsethigh = di->ddoffsethigh;
- }
-#if defined(__mips__) && defined(IL_BIGENDIAN)
- di->dataoffsetlow = di->dataoffsetlow + SI_SDRAM_SWAPPED;
-#endif /* defined(__mips__) && defined(IL_BIGENDIAN) */
+ /* add offset for pcie with DMA64 bus */
+ di->ddoffsetlow = 0;
+ di->ddoffsethigh = SI_PCIE_DMA_H32;
+ di->dataoffsetlow = di->ddoffsetlow;
+ di->dataoffsethigh = di->ddoffsethigh;
/* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */
if ((ai_coreid(sih) == SDIOD_CORE_ID)
&& ((ai_corerev(sih) > 0) && (ai_corerev(sih) <= 2)))
@@ -524,16 +633,16 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
else
di->addrext = _dma_isaddrext(di);
- /* does the descriptors need to be aligned and if yes, on 4K/8K or not */
+ /* does the descriptor need to be aligned and if yes, on 4K/8K or not */
di->aligndesc_4k = _dma_descriptor_align(di);
if (di->aligndesc_4k) {
di->dmadesc_align = D64RINGALIGN_BITS;
- if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2)) {
+ if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2))
/* for smaller dd table, HW relax alignment reqmnt */
di->dmadesc_align = D64RINGALIGN_BITS - 1;
- }
- } else
+ } else {
di->dmadesc_align = 4; /* 16 byte alignment */
+ }
DMA_NONE(("DMA descriptor align_needed %d, align %d\n",
di->aligndesc_4k, di->dmadesc_align));
@@ -542,148 +651,97 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
if (ntxd) {
size = ntxd * sizeof(void *);
di->txp = kzalloc(size, GFP_ATOMIC);
- if (di->txp == NULL) {
- DMA_ERROR(("%s: dma_attach: out of tx memory\n", di->name));
+ if (di->txp == NULL)
goto fail;
- }
}
/* allocate rx packet pointer vector */
if (nrxd) {
size = nrxd * sizeof(void *);
di->rxp = kzalloc(size, GFP_ATOMIC);
- if (di->rxp == NULL) {
- DMA_ERROR(("%s: dma_attach: out of rx memory\n", di->name));
+ if (di->rxp == NULL)
goto fail;
- }
}
- /* allocate transmit descriptor ring, only need ntxd descriptors but it must be aligned */
+ /*
+ * allocate transmit descriptor ring, only need ntxd descriptors
+ * but it must be aligned
+ */
if (ntxd) {
if (!_dma_alloc(di, DMA_TX))
goto fail;
}
- /* allocate receive descriptor ring, only need nrxd descriptors but it must be aligned */
+ /*
+ * allocate receive descriptor ring, only need nrxd descriptors
+ * but it must be aligned
+ */
if (nrxd) {
if (!_dma_alloc(di, DMA_RX))
goto fail;
}
if ((di->ddoffsetlow != 0) && !di->addrext) {
- if (PHYSADDRLO(di->txdpa) > SI_PCI_DMA_SZ) {
- DMA_ERROR(("%s: dma_attach: txdpa 0x%x: addrext not supported\n", di->name, (u32) PHYSADDRLO(di->txdpa)));
+ if (di->txdpa > SI_PCI_DMA_SZ) {
+ DMA_ERROR(("%s: dma_attach: txdpa 0x%x: addrext not "
+ "supported\n", di->name, (u32)di->txdpa));
goto fail;
}
- if (PHYSADDRLO(di->rxdpa) > SI_PCI_DMA_SZ) {
- DMA_ERROR(("%s: dma_attach: rxdpa 0x%x: addrext not supported\n", di->name, (u32) PHYSADDRLO(di->rxdpa)));
+ if (di->rxdpa > SI_PCI_DMA_SZ) {
+ DMA_ERROR(("%s: dma_attach: rxdpa 0x%x: addrext not "
+ "supported\n", di->name, (u32)di->rxdpa));
goto fail;
}
}
- DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh " "0x%x addrext %d\n", di->ddoffsetlow, di->ddoffsethigh, di->dataoffsetlow, di->dataoffsethigh, di->addrext));
-
- /* allocate DMA mapping vectors */
- if (DMASGLIST_ENAB) {
- if (ntxd) {
- size = ntxd * sizeof(struct dma_seg_map);
- di->txp_dmah = kzalloc(size, GFP_ATOMIC);
- if (di->txp_dmah == NULL)
- goto fail;
- }
-
- if (nrxd) {
- size = nrxd * sizeof(struct dma_seg_map);
- di->rxp_dmah = kzalloc(size, GFP_ATOMIC);
- if (di->rxp_dmah == NULL)
- goto fail;
- }
- }
+ DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x "
+ "dataoffsethigh " "0x%x addrext %d\n", di->ddoffsetlow,
+ di->ddoffsethigh, di->dataoffsetlow, di->dataoffsethigh,
+ di->addrext));
return (struct dma_pub *) di;
fail:
- _dma_detach(di);
+ dma_detach((struct dma_pub *)di);
return NULL;
}
-/* Check for odd number of 1's */
-static inline u32 parity32(u32 data)
-{
- data ^= data >> 16;
- data ^= data >> 8;
- data ^= data >> 4;
- data ^= data >> 2;
- data ^= data >> 1;
-
- return data & 1;
-}
-
-#define DMA64_DD_PARITY(dd) parity32((dd)->addrlow ^ (dd)->addrhigh ^ (dd)->ctrl1 ^ (dd)->ctrl2)
-
static inline void
dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring,
- dmaaddr_t pa, uint outidx, u32 *flags, u32 bufcount)
+ dma_addr_t pa, uint outidx, u32 *flags, u32 bufcount)
{
u32 ctrl2 = bufcount & D64_CTRL2_BC_MASK;
/* PCI bus with big(>1G) physical address, use address extension */
-#if defined(__mips__) && defined(IL_BIGENDIAN)
- if ((di->dataoffsetlow == SI_SDRAM_SWAPPED)
- || !(PHYSADDRLO(pa) & PCI32ADDR_HIGH)) {
-#else
- if ((di->dataoffsetlow == 0) || !(PHYSADDRLO(pa) & PCI32ADDR_HIGH)) {
-#endif /* defined(__mips__) && defined(IL_BIGENDIAN) */
-
- W_SM(&ddring[outidx].addrlow,
- BUS_SWAP32(PHYSADDRLO(pa) + di->dataoffsetlow));
- W_SM(&ddring[outidx].addrhigh,
- BUS_SWAP32(PHYSADDRHI(pa) + di->dataoffsethigh));
- W_SM(&ddring[outidx].ctrl1, BUS_SWAP32(*flags));
- W_SM(&ddring[outidx].ctrl2, BUS_SWAP32(ctrl2));
+ if ((di->dataoffsetlow == 0) || !(pa & PCI32ADDR_HIGH)) {
+ ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow);
+ ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh);
+ ddring[outidx].ctrl1 = cpu_to_le32(*flags);
+ ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
} else {
/* address extension for 32-bit PCI */
u32 ae;
- ae = (PHYSADDRLO(pa) & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
- PHYSADDRLO(pa) &= ~PCI32ADDR_HIGH;
+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
+ pa &= ~PCI32ADDR_HIGH;
ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE;
- W_SM(&ddring[outidx].addrlow,
- BUS_SWAP32(PHYSADDRLO(pa) + di->dataoffsetlow));
- W_SM(&ddring[outidx].addrhigh,
- BUS_SWAP32(0 + di->dataoffsethigh));
- W_SM(&ddring[outidx].ctrl1, BUS_SWAP32(*flags));
- W_SM(&ddring[outidx].ctrl2, BUS_SWAP32(ctrl2));
+ ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow);
+ ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh);
+ ddring[outidx].ctrl1 = cpu_to_le32(*flags);
+ ddring[outidx].ctrl2 = cpu_to_le32(ctrl2);
}
if (di->dma.dmactrlflags & DMA_CTRL_PEN) {
- if (DMA64_DD_PARITY(&ddring[outidx])) {
- W_SM(&ddring[outidx].ctrl2,
- BUS_SWAP32(ctrl2 | D64_CTRL2_PARITY));
- }
- }
-}
-
-static bool _dma_alloc(struct dma_info *di, uint direction)
-{
- return dma64_alloc(di, direction);
-}
-
-void *dma_alloc_consistent(struct pci_dev *pdev, uint size, u16 align_bits,
- uint *alloced, unsigned long *pap)
-{
- if (align_bits) {
- u16 align = (1 << align_bits);
- if (!IS_ALIGNED(PAGE_SIZE, align))
- size += align;
- *alloced = size;
+ if (dma64_dd_parity(&ddring[outidx]))
+ ddring[outidx].ctrl2 =
+ cpu_to_le32(ctrl2 | D64_CTRL2_PARITY);
}
- return pci_alloc_consistent(pdev, size, (dma_addr_t *) pap);
}
/* !! may be called with core in reset */
-static void _dma_detach(struct dma_info *di)
+void dma_detach(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
DMA_TRACE(("%s: dma_detach\n", di->name));
@@ -701,117 +759,78 @@ static void _dma_detach(struct dma_info *di)
kfree(di->txp);
kfree(di->rxp);
- /* free tx packet DMA handles */
- kfree(di->txp_dmah);
-
- /* free rx packet DMA handles */
- kfree(di->rxp_dmah);
-
/* free our private info structure */
kfree(di);
}
-static bool _dma_descriptor_align(struct dma_info *di)
-{
- u32 addrl;
-
- /* Check to see if the descriptors need to be aligned on 4K/8K or not */
- if (di->d64txregs != NULL) {
- W_REG(&di->d64txregs->addrlow, 0xff0);
- addrl = R_REG(&di->d64txregs->addrlow);
- if (addrl != 0)
- return false;
- } else if (di->d64rxregs != NULL) {
- W_REG(&di->d64rxregs->addrlow, 0xff0);
- addrl = R_REG(&di->d64rxregs->addrlow);
- if (addrl != 0)
- return false;
- }
- return true;
-}
-
-/* return true if this dma engine supports DmaExtendedAddrChanges, otherwise false */
-static bool _dma_isaddrext(struct dma_info *di)
-{
- /* DMA64 supports full 32- or 64-bit operation. AE is always valid */
-
- /* not all tx or rx channel are available */
- if (di->d64txregs != NULL) {
- if (!_dma64_addrext(di->d64txregs)) {
- DMA_ERROR(("%s: _dma_isaddrext: DMA64 tx doesn't have "
- "AE set\n", di->name));
- }
- return true;
- } else if (di->d64rxregs != NULL) {
- if (!_dma64_addrext(di->d64rxregs)) {
- DMA_ERROR(("%s: _dma_isaddrext: DMA64 rx doesn't have "
- "AE set\n", di->name));
- }
- return true;
- }
- return false;
-}
-
/* initialize descriptor table base address */
-static void _dma_ddtable_init(struct dma_info *di, uint direction, dmaaddr_t pa)
+static void
+_dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa)
{
if (!di->aligndesc_4k) {
if (direction == DMA_TX)
- di->xmtptrbase = PHYSADDRLO(pa);
+ di->xmtptrbase = pa;
else
- di->rcvptrbase = PHYSADDRLO(pa);
+ di->rcvptrbase = pa;
}
if ((di->ddoffsetlow == 0)
- || !(PHYSADDRLO(pa) & PCI32ADDR_HIGH)) {
+ || !(pa & PCI32ADDR_HIGH)) {
if (direction == DMA_TX) {
- W_REG(&di->d64txregs->addrlow,
- (PHYSADDRLO(pa) + di->ddoffsetlow));
- W_REG(&di->d64txregs->addrhigh,
- (PHYSADDRHI(pa) + di->ddoffsethigh));
+ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh);
} else {
- W_REG(&di->d64rxregs->addrlow,
- (PHYSADDRLO(pa) + di->ddoffsetlow));
- W_REG(&di->d64rxregs->addrhigh,
- (PHYSADDRHI(pa) + di->ddoffsethigh));
+ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh);
}
} else {
/* DMA64 32bits address extension */
u32 ae;
/* shift the high bit(s) from pa to ae */
- ae = (PHYSADDRLO(pa) & PCI32ADDR_HIGH) >>
- PCI32ADDR_HIGH_SHIFT;
- PHYSADDRLO(pa) &= ~PCI32ADDR_HIGH;
+ ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT;
+ pa &= ~PCI32ADDR_HIGH;
if (direction == DMA_TX) {
- W_REG(&di->d64txregs->addrlow,
- (PHYSADDRLO(pa) + di->ddoffsetlow));
- W_REG(&di->d64txregs->addrhigh,
- di->ddoffsethigh);
+ W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh);
SET_REG(&di->d64txregs->control,
D64_XC_AE, (ae << D64_XC_AE_SHIFT));
} else {
- W_REG(&di->d64rxregs->addrlow,
- (PHYSADDRLO(pa) + di->ddoffsetlow));
- W_REG(&di->d64rxregs->addrhigh,
- di->ddoffsethigh);
+ W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow);
+ W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh);
SET_REG(&di->d64rxregs->control,
D64_RC_AE, (ae << D64_RC_AE_SHIFT));
}
}
}
-static void _dma_fifoloopbackenable(struct dma_info *di)
+static void _dma_rxenable(struct dma_info *di)
{
- DMA_TRACE(("%s: dma_fifoloopbackenable\n", di->name));
+ uint dmactrlflags = di->dma.dmactrlflags;
+ u32 control;
+
+ DMA_TRACE(("%s: dma_rxenable\n", di->name));
+
+ control =
+ (R_REG(&di->d64rxregs->control) & D64_RC_AE) |
+ D64_RC_RE;
+
+ if ((dmactrlflags & DMA_CTRL_PEN) == 0)
+ control |= D64_RC_PD;
- OR_REG(&di->d64txregs->control, D64_XC_LE);
+ if (dmactrlflags & DMA_CTRL_ROC)
+ control |= D64_RC_OC;
+
+ W_REG(&di->d64rxregs->control,
+ ((di->rxoffset << D64_RC_RO_SHIFT) | control));
}
-static void _dma_rxinit(struct dma_info *di)
+void dma_rxinit(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
+
DMA_TRACE(("%s: dma_rxinit\n", di->name));
if (di->nrxd == 0)
@@ -820,8 +839,7 @@ static void _dma_rxinit(struct dma_info *di)
di->rxin = di->rxout = 0;
/* clear rx descriptor ring */
- memset((void *)di->rxd64, '\0',
- (di->nrxd * sizeof(struct dma64desc)));
+ memset(di->rxd64, '\0', di->nrxd * sizeof(struct dma64desc));
/* DMA engine with out alignment requirement requires table to be inited
* before enabling the engine
@@ -835,46 +853,64 @@ static void _dma_rxinit(struct dma_info *di)
_dma_ddtable_init(di, DMA_RX, di->rxdpa);
}
-static void _dma_rxenable(struct dma_info *di)
+static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall)
{
- uint dmactrlflags = di->dma.dmactrlflags;
- u32 control;
+ uint i, curr;
+ struct sk_buff *rxp;
+ dma_addr_t pa;
- DMA_TRACE(("%s: dma_rxenable\n", di->name));
+ i = di->rxin;
- control =
- (R_REG(&di->d64rxregs->control) & D64_RC_AE) |
- D64_RC_RE;
+ /* return if no packets posted */
+ if (i == di->rxout)
+ return NULL;
- if ((dmactrlflags & DMA_CTRL_PEN) == 0)
- control |= D64_RC_PD;
+ curr =
+ B2I(((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) -
+ di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc);
- if (dmactrlflags & DMA_CTRL_ROC)
- control |= D64_RC_OC;
+ /* ignore curr if forceall */
+ if (!forceall && (i == curr))
+ return NULL;
- W_REG(&di->d64rxregs->control,
- ((di->rxoffset << D64_RC_RO_SHIFT) | control));
+ /* get the packet pointer that corresponds to the rx descriptor */
+ rxp = di->rxp[i];
+ di->rxp[i] = NULL;
+
+ pa = le32_to_cpu(di->rxd64[i].addrlow) - di->dataoffsetlow;
+
+ /* clear this packet from the descriptor ring */
+ pci_unmap_single(di->pbus, pa, di->rxbufsize, PCI_DMA_FROMDEVICE);
+
+ di->rxd64[i].addrlow = cpu_to_le32(0xdeadbeef);
+ di->rxd64[i].addrhigh = cpu_to_le32(0xdeadbeef);
+
+ di->rxin = nextrxd(di, i);
+
+ return rxp;
}
-static void
-_dma_rx_param_get(struct dma_info *di, u16 *rxoffset, u16 *rxbufsize)
+static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
{
- /* the normal values fit into 16 bits */
- *rxoffset = (u16) di->rxoffset;
- *rxbufsize = (u16) di->rxbufsize;
+ if (di->nrxd == 0)
+ return NULL;
+
+ return dma64_getnextrxp(di, forceall);
}
-/* !! rx entry routine
+/*
+ * !! rx entry routine
* returns a pointer to the next frame received, or NULL if there are no more
- * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is supported
- * with pkts chain
+ * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is
+ * supported with pkts chain
* otherwise, it's treated as giant pkt and will be tossed.
- * The DMA scattering starts with normal DMA header, followed by first buffer data.
- * After it reaches the max size of buffer, the data continues in next DMA descriptor
- * buffer WITHOUT DMA header
+ * The DMA scattering starts with normal DMA header, followed by first
+ * buffer data. After it reaches the max size of buffer, the data continues
+ * in next DMA descriptor buffer WITHOUT DMA header
*/
-static void *_dma_rx(struct dma_info *di)
+struct sk_buff *dma_rx(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
struct sk_buff *p, *head, *tail;
uint len;
uint pkt_len;
@@ -885,7 +921,7 @@ static void *_dma_rx(struct dma_info *di)
if (head == NULL)
return NULL;
- len = le16_to_cpu(*(u16 *) (head->data));
+ len = le16_to_cpu(*(__le16 *) (head->data));
DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
dma_spin_for_len(len, head);
@@ -899,7 +935,7 @@ static void *_dma_rx(struct dma_info *di)
tail = head;
while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
tail->next = p;
- pkt_len = min(resid, (int)di->rxbufsize);
+ pkt_len = min_t(uint, resid, di->rxbufsize);
__skb_trim(p, pkt_len);
tail = p;
@@ -914,7 +950,7 @@ static void *_dma_rx(struct dma_info *di)
D64_RS0_CD_MASK) -
di->rcvptrbase) & D64_RS0_CD_MASK,
struct dma64desc);
- DMA_ERROR(("_dma_rx, rxin %d rxout %d, hw_curr %d\n",
+ DMA_ERROR(("dma_rx, rxin %d rxout %d, hw_curr %d\n",
di->rxin, di->rxout, cur));
}
#endif /* BCMDBG */
@@ -931,19 +967,32 @@ static void *_dma_rx(struct dma_info *di)
return head;
}
-/* post receive buffers
- * return false is refill failed completely and ring is empty
- * this will stall the rx dma and user might want to call rxfill again asap
- * This unlikely happens on memory-rich NIC, but often on memory-constrained dongle
+static bool dma64_rxidle(struct dma_info *di)
+{
+ DMA_TRACE(("%s: dma_rxidle\n", di->name));
+
+ if (di->nrxd == 0)
+ return true;
+
+ return ((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) ==
+ (R_REG(&di->d64rxregs->ptr) & D64_RS0_CD_MASK));
+}
+
+/*
+ * post receive buffers
+ * return false is refill failed completely and ring is empty this will stall
+ * the rx dma and user might want to call rxfill again asap. This unlikely
+ * happens on memory-rich NIC, but often on memory-constrained dongle
*/
-static bool _dma_rxfill(struct dma_info *di)
+bool dma_rxfill(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
struct sk_buff *p;
u16 rxin, rxout;
u32 flags = 0;
uint n;
uint i;
- dmaaddr_t pa;
+ dma_addr_t pa;
uint extra_offset = 0;
bool ring_empty;
@@ -958,7 +1007,7 @@ static bool _dma_rxfill(struct dma_info *di)
rxin = di->rxin;
rxout = di->rxout;
- n = di->nrxpost - NRXDACTIVE(rxin, rxout);
+ n = di->nrxpost - nrxdactive(di, rxin, rxout);
DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n));
@@ -966,10 +1015,10 @@ static bool _dma_rxfill(struct dma_info *di)
extra_offset = di->rxextrahdrroom;
for (i = 0; i < n; i++) {
- /* the di->rxbufsize doesn't include the extra headroom, we need to add it to the
- size to be allocated
+ /*
+ * the di->rxbufsize doesn't include the extra headroom,
+ * we need to add it to the size to be allocated
*/
-
p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset);
if (p == NULL) {
@@ -992,10 +1041,6 @@ static bool _dma_rxfill(struct dma_info *di)
*/
*(u32 *) (p->data) = 0;
- if (DMASGLIST_ENAB)
- memset(&di->rxp_dmah[rxout], 0,
- sizeof(struct dma_seg_map));
-
pa = pci_map_single(di->pbus, p->data,
di->rxbufsize, PCI_DMA_FROMDEVICE);
@@ -1009,7 +1054,7 @@ static bool _dma_rxfill(struct dma_info *di)
dma64_dd_upd(di, di->rxd64, pa, rxout, &flags,
di->rxbufsize);
- rxout = NEXTRXD(rxout);
+ rxout = nextrxd(di, rxout);
}
di->rxout = rxout;
@@ -1021,49 +1066,10 @@ static bool _dma_rxfill(struct dma_info *di)
return ring_empty;
}
-/* like getnexttxp but no reclaim */
-static void *_dma_peeknexttxp(struct dma_info *di)
+void dma_rxreclaim(struct dma_pub *pub)
{
- uint end, i;
-
- if (di->ntxd == 0)
- return NULL;
-
- end =
- B2I(((R_REG(&di->d64txregs->status0) &
- D64_XS0_CD_MASK) - di->xmtptrbase) & D64_XS0_CD_MASK,
- struct dma64desc);
-
- for (i = di->txin; i != end; i = NEXTTXD(i))
- if (di->txp[i])
- return di->txp[i];
-
- return NULL;
-}
-
-/* like getnextrxp but not take off the ring */
-static void *_dma_peeknextrxp(struct dma_info *di)
-{
- uint end, i;
-
- if (di->nrxd == 0)
- return NULL;
-
- end =
- B2I(((R_REG(&di->d64rxregs->status0) &
- D64_RS0_CD_MASK) - di->rcvptrbase) & D64_RS0_CD_MASK,
- struct dma64desc);
-
- for (i = di->rxin; i != end; i = NEXTRXD(i))
- if (di->rxp[i])
- return di->rxp[i];
-
- return NULL;
-}
-
-static void _dma_rxreclaim(struct dma_info *di)
-{
- void *p;
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p;
DMA_TRACE(("%s: dma_rxreclaim\n", di->name));
@@ -1071,155 +1077,29 @@ static void _dma_rxreclaim(struct dma_info *di)
brcmu_pkt_buf_free_skb(p);
}
-static void *_dma_getnextrxp(struct dma_info *di, bool forceall)
-{
- if (di->nrxd == 0)
- return NULL;
-
- return dma64_getnextrxp(di, forceall);
-}
-
-static void _dma_txblock(struct dma_info *di)
+void dma_counterreset(struct dma_pub *pub)
{
- di->dma.txavail = 0;
-}
-
-static void _dma_txunblock(struct dma_info *di)
-{
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-}
-
-static uint _dma_txactive(struct dma_info *di)
-{
- return NTXDACTIVE(di->txin, di->txout);
-}
-
-static uint _dma_txpending(struct dma_info *di)
-{
- uint curr;
-
- curr =
- B2I(((R_REG(&di->d64txregs->status0) &
- D64_XS0_CD_MASK) - di->xmtptrbase) & D64_XS0_CD_MASK,
- struct dma64desc);
-
- return NTXDACTIVE(curr, di->txout);
-}
-
-static uint _dma_txcommitted(struct dma_info *di)
-{
- uint ptr;
- uint txin = di->txin;
-
- if (txin == di->txout)
- return 0;
-
- ptr = B2I(R_REG(&di->d64txregs->ptr), struct dma64desc);
-
- return NTXDACTIVE(di->txin, ptr);
-}
-
-static uint _dma_rxactive(struct dma_info *di)
-{
- return NRXDACTIVE(di->rxin, di->rxout);
-}
-
-static void _dma_counterreset(struct dma_info *di)
-{
- /* reset all software counter */
- di->dma.rxgiants = 0;
- di->dma.rxnobuf = 0;
- di->dma.txnobuf = 0;
-}
-
-static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
-{
- uint dmactrlflags = di->dma.dmactrlflags;
-
- if (di == NULL) {
- DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name));
- return 0;
- }
-
- dmactrlflags &= ~mask;
- dmactrlflags |= flags;
-
- /* If trying to enable parity, check if parity is actually supported */
- if (dmactrlflags & DMA_CTRL_PEN) {
- u32 control;
-
- control = R_REG(&di->d64txregs->control);
- W_REG(&di->d64txregs->control,
- control | D64_XC_PD);
- if (R_REG(&di->d64txregs->control) & D64_XC_PD) {
- /* We *can* disable it so it is supported,
- * restore control register
- */
- W_REG(&di->d64txregs->control,
- control);
- } else {
- /* Not supported, don't allow it to be enabled */
- dmactrlflags &= ~DMA_CTRL_PEN;
- }
- }
-
- di->dma.dmactrlflags = dmactrlflags;
-
- return dmactrlflags;
+ /* reset all software counters */
+ pub->rxgiants = 0;
+ pub->rxnobuf = 0;
+ pub->txnobuf = 0;
}
/* get the address of the var in order to change later */
-static unsigned long _dma_getvar(struct dma_info *di, const char *name)
+unsigned long dma_getvar(struct dma_pub *pub, const char *name)
{
+ struct dma_info *di = (struct dma_info *)pub;
+
if (!strcmp(name, "&txavail"))
return (unsigned long)&(di->dma.txavail);
return 0;
}
-static
-u8 dma_align_sizetobits(uint size)
-{
- u8 bitpos = 0;
- while (size >>= 1) {
- bitpos++;
- }
- return bitpos;
-}
-
-/* This function ensures that the DMA descriptor ring will not get allocated
- * across Page boundary. If the allocation is done across the page boundary
- * at the first time, then it is freed and the allocation is done at
- * descriptor ring size aligned location. This will ensure that the ring will
- * not cross page boundary
- */
-static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size,
- u16 *alignbits, uint *alloced,
- dmaaddr_t *descpa)
-{
- void *va;
- u32 desc_strtaddr;
- u32 alignbytes = 1 << *alignbits;
-
- va = dma_alloc_consistent(di->pbus, size, *alignbits, alloced, descpa);
-
- if (NULL == va)
- return NULL;
-
- desc_strtaddr = (u32) roundup((unsigned long)va, alignbytes);
- if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr
- & boundary)) {
- *alignbits = dma_align_sizetobits(size);
- pci_free_consistent(di->pbus, size, va, *descpa);
- va = dma_alloc_consistent(di->pbus, size, *alignbits,
- alloced, descpa);
- }
- return va;
-}
-
/* 64-bit DMA functions */
-static void dma64_txinit(struct dma_info *di)
+void dma_txinit(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
u32 control = D64_XC_XE;
DMA_TRACE(("%s: dma_txinit\n", di->name));
@@ -1231,7 +1111,7 @@ static void dma64_txinit(struct dma_info *di)
di->dma.txavail = di->ntxd - 1;
/* clear tx descriptor ring */
- memset((void *)di->txd64, '\0', (di->ntxd * sizeof(struct dma64desc)));
+ memset(di->txd64, '\0', (di->ntxd * sizeof(struct dma64desc)));
/* DMA engine with out alignment requirement requires table to be inited
* before enabling the engine
@@ -1250,17 +1130,10 @@ static void dma64_txinit(struct dma_info *di)
_dma_ddtable_init(di, DMA_TX, di->txdpa);
}
-static bool dma64_txenabled(struct dma_info *di)
+void dma_txsuspend(struct dma_pub *pub)
{
- u32 xc;
+ struct dma_info *di = (struct dma_info *)pub;
- /* If the chip is dead, it is not enabled :-) */
- xc = R_REG(&di->d64txregs->control);
- return (xc != 0xffffffff) && (xc & D64_XC_XE);
-}
-
-static void dma64_txsuspend(struct dma_info *di)
-{
DMA_TRACE(("%s: dma_txsuspend\n", di->name));
if (di->ntxd == 0)
@@ -1269,8 +1142,10 @@ static void dma64_txsuspend(struct dma_info *di)
OR_REG(&di->d64txregs->control, D64_XC_SE);
}
-static void dma64_txresume(struct dma_info *di)
+void dma_txresume(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
+
DMA_TRACE(("%s: dma_txresume\n", di->name));
if (di->ntxd == 0)
@@ -1279,16 +1154,19 @@ static void dma64_txresume(struct dma_info *di)
AND_REG(&di->d64txregs->control, ~D64_XC_SE);
}
-static bool dma64_txsuspended(struct dma_info *di)
+bool dma_txsuspended(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
+
return (di->ntxd == 0) ||
((R_REG(&di->d64txregs->control) & D64_XC_SE) ==
D64_XC_SE);
}
-static void dma64_txreclaim(struct dma_info *di, enum txd_range range)
+void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
{
- void *p;
+ struct dma_info *di = (struct dma_info *)pub;
+ struct sk_buff *p;
DMA_TRACE(("%s: dma_txreclaim %s\n", di->name,
(range == DMA_RANGE_ALL) ? "all" :
@@ -1299,77 +1177,16 @@ static void dma64_txreclaim(struct dma_info *di, enum txd_range range)
if (di->txin == di->txout)
return;
- while ((p = dma64_getnexttxp(di, range))) {
+ while ((p = dma_getnexttxp(pub, range))) {
/* For unframed data, we don't have any packets to free */
if (!(di->dma.dmactrlflags & DMA_CTRL_UNFRAMED))
brcmu_pkt_buf_free_skb(p);
}
}
-static bool dma64_txstopped(struct dma_info *di)
-{
- return ((R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK) ==
- D64_XS0_XS_STOPPED);
-}
-
-static bool dma64_rxstopped(struct dma_info *di)
-{
- return ((R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK) ==
- D64_RS0_RS_STOPPED);
-}
-
-static bool dma64_alloc(struct dma_info *di, uint direction)
-{
- u16 size;
- uint ddlen;
- void *va;
- uint alloced = 0;
- u16 align;
- u16 align_bits;
-
- ddlen = sizeof(struct dma64desc);
-
- size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen);
- align_bits = di->dmadesc_align;
- align = (1 << align_bits);
-
- if (direction == DMA_TX) {
- va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
- &alloced, &di->txdpaorig);
- if (va == NULL) {
- DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(ntxd) failed\n", di->name));
- return false;
- }
- align = (1 << align_bits);
- di->txd64 = (struct dma64desc *)
- roundup((unsigned long)va, align);
- di->txdalign = (uint) ((s8 *)di->txd64 - (s8 *) va);
- PHYSADDRLOSET(di->txdpa,
- PHYSADDRLO(di->txdpaorig) + di->txdalign);
- PHYSADDRHISET(di->txdpa, PHYSADDRHI(di->txdpaorig));
- di->txdalloc = alloced;
- } else {
- va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
- &alloced, &di->rxdpaorig);
- if (va == NULL) {
- DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(nrxd) failed\n", di->name));
- return false;
- }
- align = (1 << align_bits);
- di->rxd64 = (struct dma64desc *)
- roundup((unsigned long)va, align);
- di->rxdalign = (uint) ((s8 *)di->rxd64 - (s8 *) va);
- PHYSADDRLOSET(di->rxdpa,
- PHYSADDRLO(di->rxdpaorig) + di->rxdalign);
- PHYSADDRHISET(di->rxdpa, PHYSADDRHI(di->rxdpaorig));
- di->rxdalloc = alloced;
- }
-
- return true;
-}
-
-static bool dma64_txreset(struct dma_info *di)
+bool dma_txreset(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
u32 status;
if (di->ntxd == 0)
@@ -1393,19 +1210,9 @@ static bool dma64_txreset(struct dma_info *di)
return status == D64_XS0_XS_DISABLED;
}
-static bool dma64_rxidle(struct dma_info *di)
-{
- DMA_TRACE(("%s: dma_rxidle\n", di->name));
-
- if (di->nrxd == 0)
- return true;
-
- return ((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) ==
- (R_REG(&di->d64rxregs->ptr) & D64_RS0_CD_MASK));
-}
-
-static bool dma64_rxreset(struct dma_info *di)
+bool dma_rxreset(struct dma_pub *pub)
{
+ struct dma_info *di = (struct dma_info *)pub;
u32 status;
if (di->nrxd == 0)
@@ -1419,132 +1226,21 @@ static bool dma64_rxreset(struct dma_info *di)
return status == D64_RS0_RS_DISABLED;
}
-static bool dma64_rxenabled(struct dma_info *di)
-{
- u32 rc;
-
- rc = R_REG(&di->d64rxregs->control);
- return (rc != 0xffffffff) && (rc & D64_RC_RE);
-}
-
-static bool dma64_txsuspendedidle(struct dma_info *di)
-{
-
- if (di->ntxd == 0)
- return true;
-
- if (!(R_REG(&di->d64txregs->control) & D64_XC_SE))
- return 0;
-
- if ((R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK) ==
- D64_XS0_XS_IDLE)
- return 1;
-
- return 0;
-}
-
-/* Useful when sending unframed data. This allows us to get a progress report from the DMA.
- * We return a pointer to the beginning of the DATA buffer of the current descriptor.
- * If DMA is idle, we return NULL.
- */
-static void *dma64_getpos(struct dma_info *di, bool direction)
-{
- void *va;
- bool idle;
- u32 cd_offset;
-
- if (direction == DMA_TX) {
- cd_offset =
- R_REG(&di->d64txregs->status0) & D64_XS0_CD_MASK;
- idle = !NTXDACTIVE(di->txin, di->txout);
- va = di->txp[B2I(cd_offset, struct dma64desc)];
- } else {
- cd_offset =
- R_REG(&di->d64rxregs->status0) & D64_XS0_CD_MASK;
- idle = !NRXDACTIVE(di->rxin, di->rxout);
- va = di->rxp[B2I(cd_offset, struct dma64desc)];
- }
-
- /* If DMA is IDLE, return NULL */
- if (idle) {
- DMA_TRACE(("%s: DMA idle, return NULL\n", __func__));
- va = NULL;
- }
-
- return va;
-}
-
-/* TX of unframed data
- *
- * Adds a DMA ring descriptor for the data pointed to by "buf".
- * This is for DMA of a buffer of data and is unlike other dma TX functions
- * that take a pointer to a "packet"
- * Each call to this is results in a single descriptor being added for "len" bytes of
- * data starting at "buf", it doesn't handle chained buffers.
- */
-static int
-dma64_txunframed(struct dma_info *di, void *buf, uint len, bool commit)
-{
- u16 txout;
- u32 flags = 0;
- dmaaddr_t pa; /* phys addr */
-
- txout = di->txout;
-
- /* return nonzero if out of tx descriptors */
- if (NEXTTXD(txout) == di->txin)
- goto outoftxd;
-
- if (len == 0)
- return 0;
-
- pa = pci_map_single(di->pbus, buf, len, PCI_DMA_TODEVICE);
-
- flags = (D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF);
-
- if (txout == (di->ntxd - 1))
- flags |= D64_CTRL1_EOT;
-
- dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
-
- /* save the buffer pointer - used by dma_getpos */
- di->txp[txout] = buf;
-
- txout = NEXTTXD(txout);
- /* bump the tx descriptor index */
- di->txout = txout;
-
- /* kick the chip */
- if (commit) {
- W_REG(&di->d64txregs->ptr,
- di->xmtptrbase + I2B(txout, struct dma64desc));
- }
-
- /* tx flow control */
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-
- return 0;
-
- outoftxd:
- DMA_ERROR(("%s: %s: out of txds !!!\n", di->name, __func__));
- di->dma.txavail = 0;
- di->dma.txnobuf++;
- return -1;
-}
-
-/* !! tx entry routine
+/*
+ * !! tx entry routine
* WARNING: call must check the return value for error.
- * the error(toss frames) could be fatal and cause many subsequent hard to debug problems
+ * the error(toss frames) could be fatal and cause many subsequent hard
+ * to debug problems
*/
-static int dma64_txfast(struct dma_info *di, struct sk_buff *p0,
- bool commit)
+int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit)
{
+ struct dma_info *di = (struct dma_info *)pub;
struct sk_buff *p, *next;
unsigned char *data;
uint len;
u16 txout;
u32 flags = 0;
- dmaaddr_t pa;
+ dma_addr_t pa;
DMA_TRACE(("%s: dma_txfast\n", di->name));
@@ -1555,77 +1251,46 @@ static int dma64_txfast(struct dma_info *di, struct sk_buff *p0,
* allocating and initializing transmit descriptor entries.
*/
for (p = p0; p; p = next) {
- uint nsegs, j;
- struct dma_seg_map *map;
-
data = p->data;
len = p->len;
next = p->next;
/* return nonzero if out of tx descriptors */
- if (NEXTTXD(txout) == di->txin)
+ if (nexttxd(di, txout) == di->txin)
goto outoftxd;
if (len == 0)
continue;
/* get physical address of buffer start */
- if (DMASGLIST_ENAB)
- memset(&di->txp_dmah[txout], 0,
- sizeof(struct dma_seg_map));
-
pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE);
- if (DMASGLIST_ENAB) {
- map = &di->txp_dmah[txout];
-
- /* See if all the segments can be accounted for */
- if (map->nsegs >
- (uint) (di->ntxd - NTXDACTIVE(di->txin, di->txout) -
- 1))
- goto outoftxd;
-
- nsegs = map->nsegs;
- } else
- nsegs = 1;
-
- for (j = 1; j <= nsegs; j++) {
- flags = 0;
- if (p == p0 && j == 1)
- flags |= D64_CTRL1_SOF;
+ flags = 0;
+ if (p == p0)
+ flags |= D64_CTRL1_SOF;
- /* With a DMA segment list, Descriptor table is filled
- * using the segment list instead of looping over
- * buffers in multi-chain DMA. Therefore, EOF for SGLIST is when
- * end of segment list is reached.
- */
- if ((!DMASGLIST_ENAB && next == NULL) ||
- (DMASGLIST_ENAB && j == nsegs))
- flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
- if (txout == (di->ntxd - 1))
- flags |= D64_CTRL1_EOT;
-
- if (DMASGLIST_ENAB) {
- len = map->segs[j - 1].length;
- pa = map->segs[j - 1].addr;
- }
- dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
+ /* With a DMA segment list, Descriptor table is filled
+ * using the segment list instead of looping over
+ * buffers in multi-chain DMA. Therefore, EOF for SGLIST
+ * is when end of segment list is reached.
+ */
+ if (next == NULL)
+ flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF);
+ if (txout == (di->ntxd - 1))
+ flags |= D64_CTRL1_EOT;
- txout = NEXTTXD(txout);
- }
+ dma64_dd_upd(di, di->txd64, pa, txout, &flags, len);
- /* See above. No need to loop over individual buffers */
- if (DMASGLIST_ENAB)
- break;
+ txout = nexttxd(di, txout);
}
/* if last txd eof not set, fix it */
if (!(flags & D64_CTRL1_EOF))
- W_SM(&di->txd64[PREVTXD(txout)].ctrl1,
- BUS_SWAP32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF));
+ di->txd64[prevtxd(di, txout)].ctrl1 =
+ cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF);
/* save the packet */
- di->txp[PREVTXD(txout)] = p0;
+ di->txp[prevtxd(di, txout)] = p0;
/* bump the tx descriptor index */
di->txout = txout;
@@ -1636,7 +1301,7 @@ static int dma64_txfast(struct dma_info *di, struct sk_buff *p0,
di->xmtptrbase + I2B(txout, struct dma64desc));
/* tx flow control */
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
+ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
return 0;
@@ -1658,11 +1323,12 @@ static int dma64_txfast(struct dma_info *di, struct sk_buff *p0,
* If range is DMA_RANGE_ALL, reclaim all txd(s) posted to the ring and
* return associated packet regardless of the value of hardware pointers.
*/
-static void *dma64_getnexttxp(struct dma_info *di, enum txd_range range)
+struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
{
+ struct dma_info *di = (struct dma_info *)pub;
u16 start, end, i;
u16 active_desc;
- void *txp;
+ struct sk_buff *txp;
DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name,
(range == DMA_RANGE_ALL) ? "all" :
@@ -1679,7 +1345,7 @@ static void *dma64_getnexttxp(struct dma_info *di, enum txd_range range)
if (range == DMA_RANGE_ALL)
end = di->txout;
else {
- dma64regs_t *dregs = di->d64txregs;
+ struct dma64regs __iomem *dregs = di->d64txregs;
end = (u16) (B2I(((R_REG(&dregs->status0) &
D64_XS0_CD_MASK) -
@@ -1694,45 +1360,28 @@ static void *dma64_getnexttxp(struct dma_info *di, enum txd_range range)
(active_desc - di->xmtptrbase) & D64_XS0_CD_MASK;
active_desc = B2I(active_desc, struct dma64desc);
if (end != active_desc)
- end = PREVTXD(active_desc);
+ end = prevtxd(di, active_desc);
}
}
if ((start == 0) && (end > di->txout))
goto bogus;
- for (i = start; i != end && !txp; i = NEXTTXD(i)) {
- dmaaddr_t pa;
- struct dma_seg_map *map = NULL;
- uint size, j, nsegs;
-
- PHYSADDRLOSET(pa,
- (BUS_SWAP32(R_SM(&di->txd64[i].addrlow)) -
- di->dataoffsetlow));
- PHYSADDRHISET(pa,
- (BUS_SWAP32(R_SM(&di->txd64[i].addrhigh)) -
- di->dataoffsethigh));
-
- if (DMASGLIST_ENAB) {
- map = &di->txp_dmah[i];
- size = map->origsize;
- nsegs = map->nsegs;
- } else {
- size =
- (BUS_SWAP32(R_SM(&di->txd64[i].ctrl2)) &
- D64_CTRL2_BC_MASK);
- nsegs = 1;
- }
+ for (i = start; i != end && !txp; i = nexttxd(di, i)) {
+ dma_addr_t pa;
+ uint size;
- for (j = nsegs; j > 0; j--) {
- W_SM(&di->txd64[i].addrlow, 0xdeadbeef);
- W_SM(&di->txd64[i].addrhigh, 0xdeadbeef);
+ pa = le32_to_cpu(di->txd64[i].addrlow) - di->dataoffsetlow;
- txp = di->txp[i];
- di->txp[i] = NULL;
- if (j > 1)
- i = NEXTTXD(i);
- }
+ size =
+ (le32_to_cpu(di->txd64[i].ctrl2) &
+ D64_CTRL2_BC_MASK);
+
+ di->txd64[i].addrlow = cpu_to_le32(0xdeadbeef);
+ di->txd64[i].addrhigh = cpu_to_le32(0xdeadbeef);
+
+ txp = di->txp[i];
+ di->txp[i] = NULL;
pci_unmap_single(di->pbus, pa, size, PCI_DMA_TODEVICE);
}
@@ -1740,157 +1389,16 @@ static void *dma64_getnexttxp(struct dma_info *di, enum txd_range range)
di->txin = i;
/* tx flow control */
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
+ di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
return txp;
bogus:
- DMA_NONE(("dma_getnexttxp: bogus curr: start %d end %d txout %d force %d\n", start, end, di->txout, forceall));
+ DMA_NONE(("dma_getnexttxp: bogus curr: start %d end %d txout %d "
+ "force %d\n", start, end, di->txout, forceall));
return NULL;
}
-static void *dma64_getnextrxp(struct dma_info *di, bool forceall)
-{
- uint i, curr;
- void *rxp;
- dmaaddr_t pa;
-
- i = di->rxin;
-
- /* return if no packets posted */
- if (i == di->rxout)
- return NULL;
-
- curr =
- B2I(((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) -
- di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc);
-
- /* ignore curr if forceall */
- if (!forceall && (i == curr))
- return NULL;
-
- /* get the packet pointer that corresponds to the rx descriptor */
- rxp = di->rxp[i];
- di->rxp[i] = NULL;
-
- PHYSADDRLOSET(pa,
- (BUS_SWAP32(R_SM(&di->rxd64[i].addrlow)) -
- di->dataoffsetlow));
- PHYSADDRHISET(pa,
- (BUS_SWAP32(R_SM(&di->rxd64[i].addrhigh)) -
- di->dataoffsethigh));
-
- /* clear this packet from the descriptor ring */
- pci_unmap_single(di->pbus, pa, di->rxbufsize, PCI_DMA_FROMDEVICE);
-
- W_SM(&di->rxd64[i].addrlow, 0xdeadbeef);
- W_SM(&di->rxd64[i].addrhigh, 0xdeadbeef);
-
- di->rxin = NEXTRXD(i);
-
- return rxp;
-}
-
-static bool _dma64_addrext(dma64regs_t *dma64regs)
-{
- u32 w;
- OR_REG(&dma64regs->control, D64_XC_AE);
- w = R_REG(&dma64regs->control);
- AND_REG(&dma64regs->control, ~D64_XC_AE);
- return (w & D64_XC_AE) == D64_XC_AE;
-}
-
-/*
- * Rotate all active tx dma ring entries "forward" by (ActiveDescriptor - txin).
- */
-static void dma64_txrotate(struct dma_info *di)
-{
- u16 ad;
- uint nactive;
- uint rot;
- u16 old, new;
- u32 w;
- u16 first, last;
-
- nactive = _dma_txactive(di);
- ad = (u16) (B2I((((R_REG(&di->d64txregs->status1) &
- D64_XS1_AD_MASK) - di->xmtptrbase) &
- D64_XS1_AD_MASK), struct dma64desc));
- rot = TXD(ad - di->txin);
-
- /* full-ring case is a lot harder - don't worry about this */
- if (rot >= (di->ntxd - nactive)) {
- DMA_ERROR(("%s: dma_txrotate: ring full - punt\n", di->name));
- return;
- }
-
- first = di->txin;
- last = PREVTXD(di->txout);
-
- /* move entries starting at last and moving backwards to first */
- for (old = last; old != PREVTXD(first); old = PREVTXD(old)) {
- new = TXD(old + rot);
-
- /*
- * Move the tx dma descriptor.
- * EOT is set only in the last entry in the ring.
- */
- w = BUS_SWAP32(R_SM(&di->txd64[old].ctrl1)) & ~D64_CTRL1_EOT;
- if (new == (di->ntxd - 1))
- w |= D64_CTRL1_EOT;
- W_SM(&di->txd64[new].ctrl1, BUS_SWAP32(w));
-
- w = BUS_SWAP32(R_SM(&di->txd64[old].ctrl2));
- W_SM(&di->txd64[new].ctrl2, BUS_SWAP32(w));
-
- W_SM(&di->txd64[new].addrlow, R_SM(&di->txd64[old].addrlow));
- W_SM(&di->txd64[new].addrhigh, R_SM(&di->txd64[old].addrhigh));
-
- /* zap the old tx dma descriptor address field */
- W_SM(&di->txd64[old].addrlow, BUS_SWAP32(0xdeadbeef));
- W_SM(&di->txd64[old].addrhigh, BUS_SWAP32(0xdeadbeef));
-
- /* move the corresponding txp[] entry */
- di->txp[new] = di->txp[old];
-
- /* Move the map */
- if (DMASGLIST_ENAB) {
- memcpy(&di->txp_dmah[new], &di->txp_dmah[old],
- sizeof(struct dma_seg_map));
- memset(&di->txp_dmah[old], 0,
- sizeof(struct dma_seg_map));
- }
-
- di->txp[old] = NULL;
- }
-
- /* update txin and txout */
- di->txin = ad;
- di->txout = TXD(di->txout + rot);
- di->dma.txavail = di->ntxd - NTXDACTIVE(di->txin, di->txout) - 1;
-
- /* kick the chip */
- W_REG(&di->d64txregs->ptr,
- di->xmtptrbase + I2B(di->txout, struct dma64desc));
-}
-
-uint dma_addrwidth(struct si_pub *sih, void *dmaregs)
-{
- /* Perform 64-bit checks only if we want to advertise 64-bit (> 32bit) capability) */
- /* DMA engine is 64-bit capable */
- if ((ai_core_sflags(sih, 0, 0) & SISF_DMA64) == SISF_DMA64) {
- /* backplane are 64-bit capable */
- if (ai_backplane64(sih))
- /* If bus is System Backplane or PCIE then we can access 64-bits */
- if ((sih->bustype == SI_BUS) ||
- ((sih->bustype == PCI_BUS) &&
- (sih->buscoretype == PCIE_CORE_ID)))
- return DMADDRWIDTH_64;
- }
- /* DMA hardware not supported by this driver*/
- return DMADDRWIDTH_64;
-}
-
/*
* Mac80211 initiated actions sometimes require packets in the DMA queue to be
* modified. The modified portion of the packet is not under control of the DMA
@@ -1912,6 +1420,6 @@ void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
tx_info = (struct ieee80211_tx_info *)skb->cb;
(callback_fnc)(tx_info, arg_a);
}
- i = NEXTTXD(i);
+ i = nexttxd(di, i);
}
}
diff --git a/drivers/staging/brcm80211/brcmsmac/dma.h b/drivers/staging/brcm80211/brcmsmac/dma.h
index 9c8b9a6a557e..ebc5bc546f3b 100644
--- a/drivers/staging/brcm80211/brcmsmac/dma.h
+++ b/drivers/staging/brcm80211/brcmsmac/dma.h
@@ -17,8 +17,13 @@
#ifndef _BRCM_DMA_H_
#define _BRCM_DMA_H_
+#include <linux/delay.h>
#include "types.h" /* forward structure declarations */
+/* map/unmap direction */
+#define DMA_TX 1 /* TX direction for DMA */
+#define DMA_RX 2 /* RX direction for DMA */
+
/* DMA structure:
* support two DMA engines: 32 bits address or 64 bit addressing
* basic DMA register set is per channel(transmit or receive)
@@ -38,19 +43,14 @@ struct dma32diag { /* diag access */
/* dma registers per channel(xmt or rcv) */
struct dma64regs {
- u32 control; /* enable, et al */
- u32 ptr; /* last descriptor posted to chip */
- u32 addrlow; /* descriptor ring base address low 32-bits (8K aligned) */
- u32 addrhigh; /* descriptor ring base address bits 63:32 (8K aligned) */
- u32 status0; /* current descriptor, xmt state */
- u32 status1; /* active descriptor, xmt error */
+ u32 control; /* enable, et al */
+ u32 ptr; /* last descriptor posted to chip */
+ u32 addrlow; /* desc ring base address low 32-bits (8K aligned) */
+ u32 addrhigh; /* desc ring base address bits 63:32 (8K aligned) */
+ u32 status0; /* current descriptor, xmt state */
+ u32 status1; /* active descriptor, xmt error */
};
-/* map/unmap direction */
-#define DMA_TX 1 /* TX direction for DMA */
-#define DMA_RX 2 /* RX direction for DMA */
-#define BUS_SWAP32(v) (v)
-
/* range param for dma_getnexttxp() and dma_txreclaim */
enum txd_range {
DMA_RANGE_ALL = 1,
@@ -58,110 +58,11 @@ enum txd_range {
DMA_RANGE_TRANSFERED
};
-/* dma function type */
-typedef void (*di_detach_t) (struct dma_pub *dmah);
-typedef bool(*di_txreset_t) (struct dma_pub *dmah);
-typedef bool(*di_rxreset_t) (struct dma_pub *dmah);
-typedef bool(*di_rxidle_t) (struct dma_pub *dmah);
-typedef void (*di_txinit_t) (struct dma_pub *dmah);
-typedef bool(*di_txenabled_t) (struct dma_pub *dmah);
-typedef void (*di_rxinit_t) (struct dma_pub *dmah);
-typedef void (*di_txsuspend_t) (struct dma_pub *dmah);
-typedef void (*di_txresume_t) (struct dma_pub *dmah);
-typedef bool(*di_txsuspended_t) (struct dma_pub *dmah);
-typedef bool(*di_txsuspendedidle_t) (struct dma_pub *dmah);
-typedef int (*di_txfast_t) (struct dma_pub *dmah, struct sk_buff *p,
- bool commit);
-typedef int (*di_txunframed_t) (struct dma_pub *dmah, void *p, uint len,
- bool commit);
-typedef void *(*di_getpos_t) (struct dma_pub *di, bool direction);
-typedef void (*di_fifoloopbackenable_t) (struct dma_pub *dmah);
-typedef bool(*di_txstopped_t) (struct dma_pub *dmah);
-typedef bool(*di_rxstopped_t) (struct dma_pub *dmah);
-typedef bool(*di_rxenable_t) (struct dma_pub *dmah);
-typedef bool(*di_rxenabled_t) (struct dma_pub *dmah);
-typedef void *(*di_rx_t) (struct dma_pub *dmah);
-typedef bool(*di_rxfill_t) (struct dma_pub *dmah);
-typedef void (*di_txreclaim_t) (struct dma_pub *dmah, enum txd_range range);
-typedef void (*di_rxreclaim_t) (struct dma_pub *dmah);
-typedef unsigned long (*di_getvar_t) (struct dma_pub *dmah,
- const char *name);
-typedef void *(*di_getnexttxp_t) (struct dma_pub *dmah, enum txd_range range);
-typedef void *(*di_getnextrxp_t) (struct dma_pub *dmah, bool forceall);
-typedef void *(*di_peeknexttxp_t) (struct dma_pub *dmah);
-typedef void *(*di_peeknextrxp_t) (struct dma_pub *dmah);
-typedef void (*di_rxparam_get_t) (struct dma_pub *dmah, u16 *rxoffset,
- u16 *rxbufsize);
-typedef void (*di_txblock_t) (struct dma_pub *dmah);
-typedef void (*di_txunblock_t) (struct dma_pub *dmah);
-typedef uint(*di_txactive_t) (struct dma_pub *dmah);
-typedef void (*di_txrotate_t) (struct dma_pub *dmah);
-typedef void (*di_counterreset_t) (struct dma_pub *dmah);
-typedef uint(*di_ctrlflags_t) (struct dma_pub *dmah, uint mask, uint flags);
-typedef char *(*di_dump_t) (struct dma_pub *dmah, struct brcmu_strbuf *b,
- bool dumpring);
-typedef char *(*di_dumptx_t) (struct dma_pub *dmah, struct brcmu_strbuf *b,
- bool dumpring);
-typedef char *(*di_dumprx_t) (struct dma_pub *dmah, struct brcmu_strbuf *b,
- bool dumpring);
-typedef uint(*di_rxactive_t) (struct dma_pub *dmah);
-typedef uint(*di_txpending_t) (struct dma_pub *dmah);
-typedef uint(*di_txcommitted_t) (struct dma_pub *dmah);
-
-/* dma opsvec */
-struct di_fcn_s {
- di_detach_t detach;
- di_txinit_t txinit;
- di_txreset_t txreset;
- di_txenabled_t txenabled;
- di_txsuspend_t txsuspend;
- di_txresume_t txresume;
- di_txsuspended_t txsuspended;
- di_txsuspendedidle_t txsuspendedidle;
- di_txfast_t txfast;
- di_txunframed_t txunframed;
- di_getpos_t getpos;
- di_txstopped_t txstopped;
- di_txreclaim_t txreclaim;
- di_getnexttxp_t getnexttxp;
- di_peeknexttxp_t peeknexttxp;
- di_txblock_t txblock;
- di_txunblock_t txunblock;
- di_txactive_t txactive;
- di_txrotate_t txrotate;
-
- di_rxinit_t rxinit;
- di_rxreset_t rxreset;
- di_rxidle_t rxidle;
- di_rxstopped_t rxstopped;
- di_rxenable_t rxenable;
- di_rxenabled_t rxenabled;
- di_rx_t rx;
- di_rxfill_t rxfill;
- di_rxreclaim_t rxreclaim;
- di_getnextrxp_t getnextrxp;
- di_peeknextrxp_t peeknextrxp;
- di_rxparam_get_t rxparam_get;
-
- di_fifoloopbackenable_t fifoloopbackenable;
- di_getvar_t d_getvar;
- di_counterreset_t counterreset;
- di_ctrlflags_t ctrlflags;
- di_dump_t dump;
- di_dumptx_t dumptx;
- di_dumprx_t dumprx;
- di_rxactive_t rxactive;
- di_txpending_t txpending;
- di_txcommitted_t txcommitted;
- uint endnum;
-};
-
/*
* Exported data structure (read-only)
*/
/* export structure */
struct dma_pub {
- const struct di_fcn_s *di_fn; /* DMA function pointers */
uint txavail; /* # free tx descriptors */
uint dmactrlflags; /* dma control flags */
@@ -173,78 +74,47 @@ struct dma_pub {
};
extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
- void *dmaregstx, void *dmaregsrx, uint ntxd,
- uint nrxd, uint rxbufsize, int rxextheadroom,
+ void __iomem *dmaregstx, void __iomem *dmaregsrx,
+ uint ntxd, uint nrxd,
+ uint rxbufsize, int rxextheadroom,
uint nrxpost, uint rxoffset, uint *msg_level);
-extern const struct di_fcn_s dma64proc;
-
-#define dma_detach(di) (dma64proc.detach(di))
-#define dma_txreset(di) (dma64proc.txreset(di))
-#define dma_rxreset(di) (dma64proc.rxreset(di))
-#define dma_rxidle(di) (dma64proc.rxidle(di))
-#define dma_txinit(di) (dma64proc.txinit(di))
-#define dma_txenabled(di) (dma64proc.txenabled(di))
-#define dma_rxinit(di) (dma64proc.rxinit(di))
-#define dma_txsuspend(di) (dma64proc.txsuspend(di))
-#define dma_txresume(di) (dma64proc.txresume(di))
-#define dma_txsuspended(di) (dma64proc.txsuspended(di))
-#define dma_txsuspendedidle(di) (dma64proc.txsuspendedidle(di))
-#define dma_txfast(di, p, commit) (dma64proc.txfast(di, p, commit))
-#define dma_txunframed(di, p, l, commit)(dma64proc.txunframed(di, p, l, commit))
-#define dma_getpos(di, dir) (dma64proc.getpos(di, dir))
-#define dma_fifoloopbackenable(di) (dma64proc.fifoloopbackenable(di))
-#define dma_txstopped(di) (dma64proc.txstopped(di))
-#define dma_rxstopped(di) (dma64proc.rxstopped(di))
-#define dma_rxenable(di) (dma64proc.rxenable(di))
-#define dma_rxenabled(di) (dma64proc.rxenabled(di))
-#define dma_rx(di) (dma64proc.rx(di))
-#define dma_rxfill(di) (dma64proc.rxfill(di))
-#define dma_txreclaim(di, range) (dma64proc.txreclaim(di, range))
-#define dma_rxreclaim(di) (dma64proc.rxreclaim(di))
-#define dma_getvar(di, name) (dma64proc.d_getvar(di, name))
-#define dma_getnexttxp(di, range) (dma64proc.getnexttxp(di, range))
-#define dma_getnextrxp(di, forceall) (dma64proc.getnextrxp(di, forceall))
-#define dma_peeknexttxp(di) (dma64proc.peeknexttxp(di))
-#define dma_peeknextrxp(di) (dma64proc.peeknextrxp(di))
-#define dma_rxparam_get(di, off, bufs) (dma64proc.rxparam_get(di, off, bufs))
-
-#define dma_txblock(di) (dma64proc.txblock(di))
-#define dma_txunblock(di) (dma64proc.txunblock(di))
-#define dma_txactive(di) (dma64proc.txactive(di))
-#define dma_rxactive(di) (dma64proc.rxactive(di))
-#define dma_txrotate(di) (dma64proc.txrotate(di))
-#define dma_counterreset(di) (dma64proc.counterreset(di))
-#define dma_ctrlflags(di, mask, flags) (dma64proc.ctrlflags((di), (mask), (flags)))
-#define dma_txpending(di) (dma64proc.txpending(di))
-#define dma_txcommitted(di) (dma64proc.txcommitted(di))
-
-
-/* return addresswidth allowed
- * This needs to be done after SB attach but before dma attach.
- * SB attach provides ability to probe backplane and dma core capabilities
- * This info is needed by DMA_ALLOC_CONSISTENT in dma attach
- */
-extern uint dma_addrwidth(struct si_pub *sih, void *dmaregs);
+void dma_rxinit(struct dma_pub *pub);
+struct sk_buff *dma_rx(struct dma_pub *pub);
+bool dma_rxfill(struct dma_pub *pub);
+bool dma_rxreset(struct dma_pub *pub);
+bool dma_txreset(struct dma_pub *pub);
+void dma_txinit(struct dma_pub *pub);
+int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit);
+void dma_txsuspend(struct dma_pub *pub);
+bool dma_txsuspended(struct dma_pub *pub);
+void dma_txresume(struct dma_pub *pub);
+void dma_txreclaim(struct dma_pub *pub, enum txd_range range);
+void dma_rxreclaim(struct dma_pub *pub);
+void dma_detach(struct dma_pub *pub);
+unsigned long dma_getvar(struct dma_pub *pub, const char *name);
+struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range);
+void dma_counterreset(struct dma_pub *pub);
+
void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc)
(void *pkt, void *arg_a), void *arg_a);
/*
- * DMA(Bug) on some chips seems to declare that the packet is ready, but the
- * packet length is not updated yet (by DMA) on the expected time.
+ * DMA(Bug) on bcm47xx chips seems to declare that the packet is ready, but
+ * the packet length is not updated yet (by DMA) on the expected time.
* Workaround is to hold processor till DMA updates the length, and stay off
* the bus to allow DMA update the length in buffer
*/
static inline void dma_spin_for_len(uint len, struct sk_buff *head)
{
-#if defined(__mips__)
+#if defined(CONFIG_BCM47XX)
if (!len) {
while (!(len = *(u16 *) KSEG1ADDR(head->data)))
udelay(1);
*(u16 *) (head->data) = cpu_to_le16((u16) len);
}
-#endif /* defined(__mips__) */
+#endif /* defined(CONFIG_BCM47XX) */
}
#endif /* _BRCM_DMA_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
index 3cb92fc0391a..ac8d02bd34f2 100644
--- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.c
@@ -31,38 +31,10 @@
#include "pub.h"
#include "ucode_loader.h"
#include "mac80211_if.h"
+#include "main.h"
#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */
-#define LOCK(wl) spin_lock_bh(&(wl)->lock)
-#define UNLOCK(wl) spin_unlock_bh(&(wl)->lock)
-
-/* locking from inside brcms_isr */
-#define ISR_LOCK(wl, flags)\
- do {\
- spin_lock(&(wl)->isr_lock);\
- (void)(flags); } \
- while (0)
-
-#define ISR_UNLOCK(wl, flags)\
- do {\
- spin_unlock(&(wl)->isr_lock);\
- (void)(flags); } \
- while (0)
-
-/* locking under LOCK() to synchronize with brcms_isr */
-#define INT_LOCK(wl, flags) spin_lock_irqsave(&(wl)->isr_lock, flags)
-#define INT_UNLOCK(wl, flags) spin_unlock_irqrestore(&(wl)->isr_lock, flags)
-
-static void brcms_timer(unsigned long data);
-static void _brcms_timer(struct brcms_timer *t);
-
-
-static int ieee_hw_init(struct ieee80211_hw *hw);
-static int ieee_hw_rate_init(struct ieee80211_hw *hw);
-
-static int wl_linux_watchdog(void *ctx);
-
/* Flags we support */
#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
FIF_ALLMULTI | \
@@ -72,20 +44,42 @@ static int wl_linux_watchdog(void *ctx);
FIF_OTHER_BSS | \
FIF_BCN_PRBRESP_PROMISC)
-static int n_adapters_found;
+#define CHAN2GHZ(channel, freqency, chflags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (freqency), \
+ .hw_value = (channel), \
+ .flags = chflags, \
+ .max_antenna_gain = 0, \
+ .max_power = 19, \
+}
+
+#define CHAN5GHZ(channel, chflags) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = 5000 + 5*(channel), \
+ .hw_value = (channel), \
+ .flags = chflags, \
+ .max_antenna_gain = 0, \
+ .max_power = 21, \
+}
+
+#define RATE(rate100m, _flags) { \
+ .bitrate = (rate100m), \
+ .flags = (_flags), \
+ .hw_value = (rate100m / 5), \
+}
-static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev);
-static void brcms_release_fw(struct brcms_info *wl);
+struct firmware_hdr {
+ __le32 offset;
+ __le32 len;
+ __le32 idx;
+};
-/* local prototypes */
-static void brcms_dpc(unsigned long data);
-static irqreturn_t brcms_isr(int irq, void *dev_id);
+static const char * const brcms_firmwares[MAX_FW_IMAGES] = {
+ "brcm/bcm43xx",
+ NULL
+};
-static int __devinit brcms_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent);
-static void brcms_remove(struct pci_dev *pdev);
-static void brcms_free(struct brcms_info *wl);
-static void brcms_set_basic_rate(struct wl_rateset *rs, u16 rate, bool is_br);
+static int n_adapters_found;
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
@@ -94,11 +88,10 @@ MODULE_LICENSE("Dual BSD/GPL");
/* recognized PCI IDs */
static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = {
- {PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43225 2G */
- {PCI_VENDOR_ID_BROADCOM, 0x4353, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 43224 DUAL */
- {PCI_VENDOR_ID_BROADCOM, 0x4727, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 4313 DUAL */
- /* 43224 Ven */
- {PCI_VENDOR_ID_BROADCOM, 0x0576, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */
{0}
};
@@ -107,60 +100,178 @@ MODULE_DEVICE_TABLE(pci, brcms_pci_id_table);
#ifdef BCMDBG
static int msglevel = 0xdeadbeef;
module_param(msglevel, int, 0);
-static int phymsglevel = 0xdeadbeef;
-module_param(phymsglevel, int, 0);
#endif /* BCMDBG */
-#define HW_TO_WL(hw) (hw->priv)
-#define WL_TO_HW(wl) (wl->pub->ieee_hw)
-
-/* MAC80211 callback functions */
-static int brcms_ops_start(struct ieee80211_hw *hw);
-static void brcms_ops_stop(struct ieee80211_hw *hw);
-static int brcms_ops_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-static void brcms_ops_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif);
-static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed);
-static void brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *info,
- u32 changed);
-static void brcms_ops_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags, u64 multicast);
-static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- bool set);
-static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw);
-static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw);
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf);
-static int brcms_ops_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats);
-static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- struct ieee80211_sta *sta);
-static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params);
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw);
-static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-static int brcms_ops_sta_remove(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-static int brcms_ops_ampdu_action(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta, u16 tid, u16 *ssn,
- u8 buf_size);
-static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw);
-static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop);
+static struct ieee80211_channel brcms_2ghz_chantable[] = {
+ CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN2GHZ(5, 2432, 0),
+ CHAN2GHZ(6, 2437, 0),
+ CHAN2GHZ(7, 2442, 0),
+ CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(12, 2467,
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(13, 2472,
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN2GHZ(14, 2484,
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+};
+
+static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
+ /* UNII-1 */
+ CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
+ /* UNII-2 */
+ CHAN5GHZ(52,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(56,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(60,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(64,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ /* MID */
+ CHAN5GHZ(100,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(104,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(108,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(112,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(116,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(120,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(124,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(128,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(132,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(136,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(140,
+ IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
+ IEEE80211_CHAN_NO_HT40MINUS),
+ /* UNII-3 */
+ CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),
+ CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),
+ CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+};
+
+/*
+ * The rate table is used for both 2.4G and 5G rates. The
+ * latter being a subset as it does not support CCK rates.
+ */
+static struct ieee80211_rate legacy_ratetable[] = {
+ RATE(10, 0),
+ RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),
+ RATE(60, 0),
+ RATE(90, 0),
+ RATE(120, 0),
+ RATE(180, 0),
+ RATE(240, 0),
+ RATE(360, 0),
+ RATE(480, 0),
+ RATE(540, 0),
+};
+
+static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {
+ .band = IEEE80211_BAND_2GHZ,
+ .channels = brcms_2ghz_chantable,
+ .n_channels = ARRAY_SIZE(brcms_2ghz_chantable),
+ .bitrates = legacy_ratetable,
+ .n_bitrates = ARRAY_SIZE(legacy_ratetable),
+ .ht_cap = {
+ /* from include/linux/ieee80211.h */
+ .cap = IEEE80211_HT_CAP_GRN_FLD |
+ IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+ .ht_supported = true,
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+ .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
+ .mcs = {
+ /* placeholders for now */
+ .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
+ .rx_highest = cpu_to_le16(500),
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
+ }
+};
+
+static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {
+ .band = IEEE80211_BAND_5GHZ,
+ .channels = brcms_5ghz_nphy_chantable,
+ .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable),
+ .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET,
+ .n_bitrates = ARRAY_SIZE(legacy_ratetable) -
+ BRCMS_LEGACY_5G_RATE_OFFSET,
+ .ht_cap = {
+ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
+ IEEE80211_HT_CAP_SGI_40 |
+ IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+ .ht_supported = true,
+ .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+ .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
+ .mcs = {
+ /* placeholders for now */
+ .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
+ .rx_highest = cpu_to_le16(500),
+ .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
+ }
+};
+
+/* flags the given rate in rateset as requested */
+static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)
+{
+ u32 i;
+
+ for (i = 0; i < rs->count; i++) {
+ if (rate != (rs->rates[i] & 0x7f))
+ continue;
+
+ if (is_br)
+ rs->rates[i] |= BRCMS_RATE_FLAG;
+ else
+ rs->rates[i] &= BRCMS_RATE_MASK;
+ return;
+ }
+}
static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct brcms_info *wl = hw->priv;
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
if (!wl->pub->up) {
wiphy_err(wl->wiphy, "ops->tx called while down\n");
kfree_skb(skb);
@@ -168,21 +279,18 @@ static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
}
brcms_c_sendpkt_mac80211(wl->wlc, skb, hw);
done:
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
}
static int brcms_ops_start(struct ieee80211_hw *hw)
{
struct brcms_info *wl = hw->priv;
bool blocked;
- /*
- struct ieee80211_channel *curchan = hw->conf.channel;
- */
ieee80211_wake_queues(hw);
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
blocked = brcms_rfkill_set_hw_state(wl);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
if (!blocked)
wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
@@ -211,15 +319,18 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
return -EOPNOTSUPP;
}
- wl = HW_TO_WL(hw);
- LOCK(wl);
- err = brcms_up(wl);
- UNLOCK(wl);
+ wl = hw->priv;
+ spin_lock_bh(&wl->lock);
+ if (!wl->pub->up)
+ err = brcms_up(wl);
+ else
+ err = -ENODEV;
+ spin_unlock_bh(&wl->lock);
- if (err != 0) {
+ if (err != 0)
wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
err);
- }
+
return err;
}
@@ -228,60 +339,26 @@ brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
struct brcms_info *wl;
- wl = HW_TO_WL(hw);
+ wl = hw->priv;
/* put driver in down state */
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_down(wl);
- UNLOCK(wl);
-}
-
-/*
- * precondition: perimeter lock has been acquired
- */
-static int
-ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
- enum nl80211_channel_type type)
-{
- struct brcms_info *wl = HW_TO_WL(hw);
- int err = 0;
-
- switch (type) {
- case NL80211_CHAN_HT20:
- case NL80211_CHAN_NO_HT:
- err = brcms_c_set(wl->wlc, BRCM_SET_CHANNEL, chan->hw_value);
- break;
- case NL80211_CHAN_HT40MINUS:
- case NL80211_CHAN_HT40PLUS:
- wiphy_err(hw->wiphy,
- "%s: Need to implement 40 Mhz Channels!\n", __func__);
- err = 1;
- break;
- }
-
- if (err)
- return -EIO;
- return err;
+ spin_unlock_bh(&wl->lock);
}
static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
{
struct ieee80211_conf *conf = &hw->conf;
- struct brcms_info *wl = HW_TO_WL(hw);
+ struct brcms_info *wl = hw->priv;
int err = 0;
int new_int;
struct wiphy *wiphy = hw->wiphy;
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
- if (brcms_c_set_par(wl->wlc, IOV_BCN_LI_BCN,
- conf->listen_interval) < 0) {
- wiphy_err(wiphy, "%s: Error setting listen_interval\n",
- __func__);
- err = -EIO;
- goto config_out;
- }
- brcms_c_get_par(wl->wlc, IOV_BCN_LI_BCN, &new_int);
+ brcms_c_set_beacon_listen_interval(wl->wlc,
+ conf->listen_interval);
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR)
wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n",
@@ -293,40 +370,33 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
"true" : "false");
if (changed & IEEE80211_CONF_CHANGE_POWER) {
- if (brcms_c_set_par(wl->wlc, IOV_QTXPOWER,
- conf->power_level * 4) < 0) {
+ err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
+ if (err < 0) {
wiphy_err(wiphy, "%s: Error setting power_level\n",
__func__);
- err = -EIO;
goto config_out;
}
- brcms_c_get_par(wl->wlc, IOV_QTXPOWER, &new_int);
- if (new_int != (conf->power_level * 4))
+ new_int = brcms_c_get_tx_power(wl->wlc);
+ if (new_int != conf->power_level)
wiphy_err(wiphy, "%s: Power level req != actual, %d %d"
- "\n", __func__, conf->power_level * 4,
+ "\n", __func__, conf->power_level,
new_int);
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
- err = ieee_set_channel(hw, conf->channel, conf->channel_type);
- }
- if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
- if (brcms_c_set
- (wl->wlc, BRCM_SET_SRL,
- conf->short_frame_max_tx_count) < 0) {
- wiphy_err(wiphy, "%s: Error setting srl\n", __func__);
- err = -EIO;
- goto config_out;
- }
- if (brcms_c_set(wl->wlc, BRCM_SET_LRL,
- conf->long_frame_max_tx_count) < 0) {
- wiphy_err(wiphy, "%s: Error setting lrl\n", __func__);
- err = -EIO;
- goto config_out;
- }
+ if (conf->channel_type == NL80211_CHAN_HT20 ||
+ conf->channel_type == NL80211_CHAN_NO_HT)
+ err = brcms_c_set_channel(wl->wlc,
+ conf->channel->hw_value);
+ else
+ err = -ENOTSUPP;
}
+ if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+ err = brcms_c_set_rate_limit(wl->wlc,
+ conf->short_frame_max_tx_count,
+ conf->long_frame_max_tx_count);
config_out:
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
return err;
}
@@ -335,9 +405,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
{
- struct brcms_info *wl = HW_TO_WL(hw);
+ struct brcms_info *wl = hw->priv;
struct wiphy *wiphy = hw->wiphy;
- int val;
if (changed & BSS_CHANGED_ASSOC) {
/* association status changed (associated/disassociated)
@@ -345,51 +414,48 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
*/
wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME,
__func__, info->assoc ? "" : "dis");
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_associate_upd(wl->wlc, info->assoc);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
}
if (changed & BSS_CHANGED_ERP_SLOT) {
+ s8 val;
+
/* slot timing changed */
if (info->use_short_slot)
val = 1;
else
val = 0;
- LOCK(wl);
- brcms_c_set(wl->wlc, BRCMS_SET_SHORTSLOT_OVERRIDE, val);
- UNLOCK(wl);
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_shortslot_override(wl->wlc, val);
+ spin_unlock_bh(&wl->lock);
}
if (changed & BSS_CHANGED_HT) {
/* 802.11n parameters changed */
u16 mode = info->ht_operation_mode;
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG,
mode & IEEE80211_HT_OP_MODE_PROTECTION);
brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF,
mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS,
mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
}
if (changed & BSS_CHANGED_BASIC_RATES) {
struct ieee80211_supported_band *bi;
u32 br_mask, i;
u16 rate;
- struct wl_rateset rs;
+ struct brcm_rateset rs;
int error;
/* retrieve the current rates */
- LOCK(wl);
- error = brcms_c_ioctl(wl->wlc, BRCM_GET_CURR_RATESET,
- &rs, sizeof(rs), NULL);
- UNLOCK(wl);
- if (error) {
- wiphy_err(wiphy, "%s: retrieve rateset failed: %d\n",
- __func__, error);
- return;
- }
+ spin_lock_bh(&wl->lock);
+ brcms_c_get_current_rateset(wl->wlc, &rs);
+ spin_unlock_bh(&wl->lock);
+
br_mask = info->basic_rates;
bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)];
for (i = 0; i < bi->n_bitrates; i++) {
@@ -402,49 +468,55 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
}
/* update the rate set */
- LOCK(wl);
- brcms_c_ioctl(wl->wlc, BRCM_SET_RATESET, &rs, sizeof(rs), NULL);
- UNLOCK(wl);
+ spin_lock_bh(&wl->lock);
+ error = brcms_c_set_rateset(wl->wlc, &rs);
+ spin_unlock_bh(&wl->lock);
+ if (error)
+ wiphy_err(wiphy, "changing basic rates failed: %d\n",
+ error);
}
if (changed & BSS_CHANGED_BEACON_INT) {
/* Beacon interval changed */
- LOCK(wl);
- brcms_c_set(wl->wlc, BRCM_SET_BCNPRD, info->beacon_int);
- UNLOCK(wl);
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_beacon_period(wl->wlc, info->beacon_int);
+ spin_unlock_bh(&wl->lock);
}
if (changed & BSS_CHANGED_BSSID) {
/* BSSID changed, for whatever reason (IBSS and managed mode) */
- LOCK(wl);
- brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET,
- info->bssid);
- UNLOCK(wl);
+ spin_lock_bh(&wl->lock);
+ brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
+ spin_unlock_bh(&wl->lock);
}
- if (changed & BSS_CHANGED_BEACON) {
+ if (changed & BSS_CHANGED_BEACON)
/* Beacon data changed, retrieve new beacon (beaconing modes) */
wiphy_err(wiphy, "%s: beacon changed\n", __func__);
- }
+
if (changed & BSS_CHANGED_BEACON_ENABLED) {
/* Beaconing should be enabled/disabled (beaconing modes) */
wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__,
info->enable_beacon ? "true" : "false");
}
+
if (changed & BSS_CHANGED_CQM) {
/* Connection quality monitor config changed */
wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d "
" (implement)\n", __func__, info->cqm_rssi_thold,
info->cqm_rssi_hyst);
}
+
if (changed & BSS_CHANGED_IBSS) {
/* IBSS join status changed */
wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__,
info->ibss_joined ? "true" : "false");
}
+
if (changed & BSS_CHANGED_ARP_FILTER) {
/* Hardware ARP filter address list or state changed */
wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d"
" (implement)\n", __func__, info->arp_filter_enabled ?
"true" : "false", info->arp_addr_cnt);
}
+
if (changed & BSS_CHANGED_QOS) {
/*
* QoS for this association was enabled/disabled.
@@ -479,7 +551,7 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & FIF_OTHER_BSS)
wiphy_err(wiphy, "FIF_OTHER_BSS\n");
if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS;
brcms_c_mac_bcn_promisc_change(wl->wlc, 1);
@@ -487,113 +559,54 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
brcms_c_mac_bcn_promisc_change(wl->wlc, 0);
wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS;
}
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
}
return;
}
-static int
-brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set)
-{
- return 0;
-}
-
static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw)
{
struct brcms_info *wl = hw->priv;
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_scan_start(wl->wlc);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
return;
}
static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw)
{
struct brcms_info *wl = hw->priv;
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_scan_stop(wl->wlc);
- UNLOCK(wl);
- return;
-}
-
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf)
-{
- wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
+ spin_unlock_bh(&wl->lock);
return;
}
static int
-brcms_ops_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
+brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
{
struct brcms_info *wl = hw->priv;
- struct wl_cnt *cnt;
-
- LOCK(wl);
- cnt = wl->pub->_cnt;
- stats->dot11ACKFailureCount = 0;
- stats->dot11RTSFailureCount = 0;
- stats->dot11FCSErrorCount = 0;
- stats->dot11RTSSuccessCount = 0;
- UNLOCK(wl);
- return 0;
-}
-static void
-brcms_ops_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd, struct ieee80211_sta *sta)
-{
- switch (cmd) {
- default:
- wiphy_err(hw->wiphy, "%s: Unknown cmd = %d\n", __func__,
- cmd);
- break;
- }
- return;
-}
-
-static int
-brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
- const struct ieee80211_tx_queue_params *params)
-{
- struct brcms_info *wl = hw->priv;
-
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_wme_setparams(wl->wlc, queue, params, true);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
return 0;
}
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw)
-{
- wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
- return 0;
-}
-
static int
brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct scb *scb;
-
- int i;
struct brcms_info *wl = hw->priv;
+ struct scb *scb = &wl->wlc->pri_scb;
- /* Init the scb */
- scb = (struct scb *)sta->drv_priv;
- memset(scb, 0, sizeof(struct scb));
- for (i = 0; i < NUMPRIO; i++)
- scb->seqctl[i] = 0xFFFF;
- scb->seqctl_nonqos = 0xFFFF;
- scb->magic = SCB_MAGIC;
+ brcms_c_init_scb(scb);
- wl->pub->global_scb = scb;
wl->pub->global_ampdu = &(scb->scb_ampdu);
wl->pub->global_ampdu->scb = scb;
wl->pub->global_ampdu->max_pdu = 16;
- brcmu_pktq_init(&scb->scb_ampdu.txq, AMPDU_MAX_SCB_TID,
- AMPDU_MAX_SCB_TID * PKTQ_LEN_DEFAULT);
sta->ht_cap.ht_supported = true;
sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
@@ -602,14 +615,10 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
- /* minstrel_ht initiates addBA on our behalf by calling ieee80211_start_tx_ba_session() */
- return 0;
-}
-
-static int
-brcms_ops_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
-{
+ /*
+ * minstrel_ht initiates addBA on our behalf by calling
+ * ieee80211_start_tx_ba_session()
+ */
return 0;
}
@@ -620,8 +629,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
- struct scb *scb = (struct scb *)sta->drv_priv;
struct brcms_info *wl = hw->priv;
+ struct scb *scb = &wl->wlc->pri_scb;
int status;
if (WARN_ON(scb->magic != SCB_MAGIC))
@@ -632,23 +641,21 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_RX_STOP:
break;
case IEEE80211_AMPDU_TX_START:
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
status = brcms_c_aggregatable(wl->wlc, tid);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
if (!status) {
wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n",
tid);
return -EINVAL;
}
- /* Future improvement: Use the starting sequence number provided ... */
- *ssn = 0;
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP:
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_ampdu_flush(wl->wlc, sta, tid);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
@@ -658,11 +665,11 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
* recipient and traffic class. 'ampdu_factor' gives maximum
* AMPDU size.
*/
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size,
(1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
sta->ht_cap.ampdu_factor)) - 1);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
/* Power save wakeup */
break;
default:
@@ -675,26 +682,26 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
{
- struct brcms_info *wl = HW_TO_WL(hw);
+ struct brcms_info *wl = hw->priv;
bool blocked;
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
blocked = brcms_c_check_radio_disabled(wl->wlc);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
}
static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
{
- struct brcms_info *wl = HW_TO_WL(hw);
+ struct brcms_info *wl = hw->priv;
no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
/* wait for packet queue and dma fifos to run empty */
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
brcms_c_wait_for_tx_completion(wl->wlc, drop);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
}
static const struct ieee80211_ops brcms_ops = {
@@ -706,16 +713,10 @@ static const struct ieee80211_ops brcms_ops = {
.config = brcms_ops_config,
.bss_info_changed = brcms_ops_bss_info_changed,
.configure_filter = brcms_ops_configure_filter,
- .set_tim = brcms_ops_set_tim,
.sw_scan_start = brcms_ops_sw_scan_start,
.sw_scan_complete = brcms_ops_sw_scan_complete,
- .set_tsf = brcms_ops_set_tsf,
- .get_stats = brcms_ops_get_stats,
- .sta_notify = brcms_ops_sta_notify,
.conf_tx = brcms_ops_conf_tx,
- .get_tsf = brcms_ops_get_tsf,
.sta_add = brcms_ops_sta_add,
- .sta_remove = brcms_ops_sta_remove,
.ampdu_action = brcms_ops_ampdu_action,
.rfkill_poll = brcms_ops_rfkill_poll,
.flush = brcms_ops_flush,
@@ -729,6 +730,284 @@ static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
}
+void brcms_dpc(unsigned long data)
+{
+ struct brcms_info *wl;
+
+ wl = (struct brcms_info *) data;
+
+ spin_lock_bh(&wl->lock);
+
+ /* call the common second level interrupt handler */
+ if (wl->pub->up) {
+ if (wl->resched) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->isr_lock, flags);
+ brcms_c_intrsupd(wl->wlc);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
+ }
+
+ wl->resched = brcms_c_dpc(wl->wlc, true);
+ }
+
+ /* brcms_c_dpc() may bring the driver down */
+ if (!wl->pub->up)
+ goto done;
+
+ /* re-schedule dpc */
+ if (wl->resched)
+ tasklet_schedule(&wl->tasklet);
+ else
+ /* re-enable interrupts */
+ brcms_intrson(wl);
+
+ done:
+ spin_unlock_bh(&wl->lock);
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
+{
+ int status;
+ struct device *device = &pdev->dev;
+ char fw_name[100];
+ int i;
+
+ memset(&wl->fw, 0, sizeof(struct brcms_firmware));
+ for (i = 0; i < MAX_FW_IMAGES; i++) {
+ if (brcms_firmwares[i] == NULL)
+ break;
+ sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
+ UCODE_LOADER_API_VER);
+ status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
+ if (status) {
+ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+ KBUILD_MODNAME, fw_name);
+ return status;
+ }
+ sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
+ UCODE_LOADER_API_VER);
+ status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
+ if (status) {
+ wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+ KBUILD_MODNAME, fw_name);
+ return status;
+ }
+ wl->fw.hdr_num_entries[i] =
+ wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
+ }
+ wl->fw.fw_cnt = i;
+ return brcms_ucode_data_init(wl, &wl->ucode);
+}
+
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static void brcms_release_fw(struct brcms_info *wl)
+{
+ int i;
+ for (i = 0; i < MAX_FW_IMAGES; i++) {
+ release_firmware(wl->fw.fw_bin[i]);
+ release_firmware(wl->fw.fw_hdr[i]);
+ }
+}
+
+/**
+ * This function frees the WL per-device resources.
+ *
+ * This function frees resources owned by the WL device pointed to
+ * by the wl parameter.
+ *
+ * precondition: can both be called locked and unlocked
+ *
+ */
+static void brcms_free(struct brcms_info *wl)
+{
+ struct brcms_timer *t, *next;
+
+ /* free ucode data */
+ if (wl->fw.fw_cnt)
+ brcms_ucode_data_free(&wl->ucode);
+ if (wl->irq)
+ free_irq(wl->irq, wl);
+
+ /* kill dpc */
+ tasklet_kill(&wl->tasklet);
+
+ if (wl->pub)
+ brcms_c_module_unregister(wl->pub, "linux", wl);
+
+ /* free common resources */
+ if (wl->wlc) {
+ brcms_c_detach(wl->wlc);
+ wl->wlc = NULL;
+ wl->pub = NULL;
+ }
+
+ /* virtual interface deletion is deferred so we cannot spinwait */
+
+ /* wait for all pending callbacks to complete */
+ while (atomic_read(&wl->callbacks) > 0)
+ schedule();
+
+ /* free timers */
+ for (t = wl->timers; t; t = next) {
+ next = t->next;
+#ifdef BCMDBG
+ kfree(t->name);
+#endif
+ kfree(t);
+ }
+
+ /*
+ * unregister_netdev() calls get_stats() which may read chip
+ * registers so we cannot unmap the chip registers until
+ * after calling unregister_netdev() .
+ */
+ if (wl->regsva)
+ iounmap(wl->regsva);
+
+ wl->regsva = NULL;
+}
+
+/*
+* called from both kernel as from this kernel module.
+* precondition: perimeter lock is not acquired.
+*/
+static void brcms_remove(struct pci_dev *pdev)
+{
+ struct brcms_info *wl;
+ struct ieee80211_hw *hw;
+ int status;
+
+ hw = pci_get_drvdata(pdev);
+ wl = hw->priv;
+ if (!wl) {
+ pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
+ return;
+ }
+
+ spin_lock_bh(&wl->lock);
+ status = brcms_c_chipmatch(pdev->vendor, pdev->device);
+ spin_unlock_bh(&wl->lock);
+ if (!status) {
+ wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
+ "failed\n");
+ return;
+ }
+ if (wl->wlc) {
+ wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
+ wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+ ieee80211_unregister_hw(hw);
+ spin_lock_bh(&wl->lock);
+ brcms_down(wl);
+ spin_unlock_bh(&wl->lock);
+ }
+ pci_disable_device(pdev);
+
+ brcms_free(wl);
+
+ pci_set_drvdata(pdev, NULL);
+ ieee80211_free_hw(hw);
+}
+
+static irqreturn_t brcms_isr(int irq, void *dev_id)
+{
+ struct brcms_info *wl;
+ bool ours, wantdpc;
+
+ wl = (struct brcms_info *) dev_id;
+
+ spin_lock(&wl->isr_lock);
+
+ /* call common first level interrupt handler */
+ ours = brcms_c_isr(wl->wlc, &wantdpc);
+ if (ours) {
+ /* if more to do... */
+ if (wantdpc) {
+
+ /* ...and call the second level interrupt handler */
+ /* schedule dpc */
+ tasklet_schedule(&wl->tasklet);
+ }
+ }
+
+ spin_unlock(&wl->isr_lock);
+
+ return IRQ_RETVAL(ours);
+}
+
+/*
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static int ieee_hw_rate_init(struct ieee80211_hw *hw)
+{
+ struct brcms_info *wl = hw->priv;
+ struct brcms_c_info *wlc = wl->wlc;
+ struct ieee80211_supported_band *band;
+ int has_5g = 0;
+ u16 phy_type;
+
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+
+ phy_type = brcms_c_get_phy_type(wl->wlc, 0);
+ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {
+ band = &wlc->bandstate[BAND_2G_INDEX]->band;
+ *band = brcms_band_2GHz_nphy_template;
+ if (phy_type == PHY_TYPE_LCN) {
+ /* Single stream */
+ band->ht_cap.mcs.rx_mask[1] = 0;
+ band->ht_cap.mcs.rx_highest = cpu_to_le16(72);
+ }
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band;
+ } else {
+ return -EPERM;
+ }
+
+ /* Assume all bands use the same phy. True for 11n devices. */
+ if (wl->pub->_nbands > 1) {
+ has_5g++;
+ if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {
+ band = &wlc->bandstate[BAND_5G_INDEX]->band;
+ *band = brcms_band_5GHz_nphy_template;
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band;
+ } else {
+ return -EPERM;
+ }
+ }
+ return 0;
+}
+
+/*
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static int ieee_hw_init(struct ieee80211_hw *hw)
+{
+ hw->flags = IEEE80211_HW_SIGNAL_DBM
+ /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
+ | IEEE80211_HW_REPORTS_TX_ACK_STATUS
+ | IEEE80211_HW_AMPDU_AGGREGATION;
+
+ hw->extra_tx_headroom = brcms_c_get_header_len();
+ hw->queues = N_TX_QUEUES;
+ hw->max_rates = 2; /* Primary rate and 1 fallback rate */
+
+ /* channel change time is dependent on chip and band */
+ hw->channel_change_time = 7 * 1000;
+ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+
+ hw->rate_control_algorithm = "minstrel_ht";
+
+ hw->sta_data_size = 0;
+ return ieee_hw_rate_init(hw);
+}
+
/**
* attach to the WL device.
*
@@ -744,21 +1023,19 @@ static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
* is called in brcms_pci_probe() context, therefore no locking required.
*/
static struct brcms_info *brcms_attach(u16 vendor, u16 device,
- unsigned long regs,
- uint bustype, void *btparam, uint irq)
+ resource_size_t regs,
+ struct pci_dev *btparam, uint irq)
{
struct brcms_info *wl = NULL;
int unit, err;
- unsigned long base_addr;
struct ieee80211_hw *hw;
u8 perm[ETH_ALEN];
unit = n_adapters_found;
err = 0;
- if (unit < 0) {
+ if (unit < 0)
return NULL;
- }
/* allocate private info */
hw = pci_get_drvdata(btparam); /* btparam == pdev */
@@ -773,19 +1050,7 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
/* setup the bottom half handler */
tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
-
-
- base_addr = regs;
-
- if (bustype == PCI_BUS || bustype == RPC_BUS) {
- /* Do nothing */
- } else {
- bustype = PCI_BUS;
- BCMMSG(wl->wiphy, "force to PCI\n");
- }
- wl->bcm_bustype = bustype;
-
- wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ);
+ wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ);
if (wl->regsva == NULL) {
wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit);
goto fail;
@@ -794,17 +1059,17 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
spin_lock_init(&wl->isr_lock);
/* prepare ucode */
- if (brcms_request_fw(wl, (struct pci_dev *)btparam) < 0) {
+ if (brcms_request_fw(wl, btparam) < 0) {
wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
"%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
brcms_release_fw(wl);
- brcms_remove((struct pci_dev *)btparam);
+ brcms_remove(btparam);
return NULL;
}
/* common load-time initialization */
- wl->wlc = brcms_c_attach((void *)wl, vendor, device, unit, false,
- wl->regsva, wl->bcm_bustype, btparam, &err);
+ wl->wlc = brcms_c_attach(wl, vendor, device, unit, false,
+ wl->regsva, btparam, &err);
brcms_release_fw(wl);
if (!wl->wlc) {
wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
@@ -815,10 +1080,8 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
wl->pub->ieee_hw = hw;
- if (brcms_c_set_par(wl->wlc, IOV_MPC, 0) < 0) {
- wiphy_err(wl->wiphy, "wl%d: Error setting MPC variable to 0\n",
- unit);
- }
+ /* disable mpc */
+ brcms_c_set_radio_mpc(wl->wlc, false);
/* register our interrupt handler */
if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
@@ -828,7 +1091,7 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
wl->irq = irq;
/* register module */
- brcms_c_module_register(wl->pub, "linux", wl, wl_linux_watchdog, NULL);
+ brcms_c_module_register(wl->pub, "linux", wl, NULL);
if (ieee_hw_init(hw)) {
wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit,
@@ -842,19 +1105,17 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
SET_IEEE80211_PERM_ADDR(hw, perm);
err = ieee80211_register_hw(hw);
- if (err) {
+ if (err)
wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
"%d\n", __func__, err);
- }
if (wl->pub->srom_ccode[0])
err = brcms_set_hint(wl, wl->pub->srom_ccode);
else
err = brcms_set_hint(wl, "US");
- if (err) {
+ if (err)
wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
__func__, err);
- }
n_adapters_found++;
return wl;
@@ -866,241 +1127,6 @@ fail:
-#define CHAN2GHZ(channel, freqency, chflags) { \
- .band = IEEE80211_BAND_2GHZ, \
- .center_freq = (freqency), \
- .hw_value = (channel), \
- .flags = chflags, \
- .max_antenna_gain = 0, \
- .max_power = 19, \
-}
-
-static struct ieee80211_channel brcms_2ghz_chantable[] = {
- CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN2GHZ(5, 2432, 0),
- CHAN2GHZ(6, 2437, 0),
- CHAN2GHZ(7, 2442, 0),
- CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN2GHZ(12, 2467,
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_NO_HT40PLUS),
- CHAN2GHZ(13, 2472,
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_NO_HT40PLUS),
- CHAN2GHZ(14, 2484,
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
-};
-
-#define CHAN5GHZ(channel, chflags) { \
- .band = IEEE80211_BAND_5GHZ, \
- .center_freq = 5000 + 5*(channel), \
- .hw_value = (channel), \
- .flags = chflags, \
- .max_antenna_gain = 0, \
- .max_power = 21, \
-}
-
-static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
- /* UNII-1 */
- CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
- /* UNII-2 */
- CHAN5GHZ(52,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(56,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(60,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(64,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- /* MID */
- CHAN5GHZ(100,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(104,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(108,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(112,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(116,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(120,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(124,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(128,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(132,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(136,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(140,
- IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
- IEEE80211_CHAN_NO_HT40MINUS),
- /* UNII-3 */
- CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),
- CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),
- CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
-};
-
-#define RATE(rate100m, _flags) { \
- .bitrate = (rate100m), \
- .flags = (_flags), \
- .hw_value = (rate100m / 5), \
-}
-
-/*
- * The rate table is used for both 2.4G and 5G rates. The
- * latter being a subset as it does not support CCK rates.
- */
-static struct ieee80211_rate legacy_ratetable[] = {
- RATE(10, 0),
- RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(60, 0),
- RATE(90, 0),
- RATE(120, 0),
- RATE(180, 0),
- RATE(240, 0),
- RATE(360, 0),
- RATE(480, 0),
- RATE(540, 0),
-};
-
-static struct ieee80211_supported_band brcms_band_2GHz_nphy = {
- .band = IEEE80211_BAND_2GHZ,
- .channels = brcms_2ghz_chantable,
- .n_channels = ARRAY_SIZE(brcms_2ghz_chantable),
- .bitrates = legacy_ratetable,
- .n_bitrates = ARRAY_SIZE(legacy_ratetable),
- .ht_cap = {
- /* from include/linux/ieee80211.h */
- .cap = IEEE80211_HT_CAP_GRN_FLD |
- IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
- .ht_supported = true,
- .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
- .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
- .mcs = {
- /* placeholders for now */
- .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
- .rx_highest = 500,
- .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
- }
-};
-
-static struct ieee80211_supported_band brcms_band_5GHz_nphy = {
- .band = IEEE80211_BAND_5GHZ,
- .channels = brcms_5ghz_nphy_chantable,
- .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable),
- .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET,
- .n_bitrates = ARRAY_SIZE(legacy_ratetable) -
- BRCMS_LEGACY_5G_RATE_OFFSET,
- .ht_cap = {
- /* use IEEE80211_HT_CAP_* from include/linux/ieee80211.h */
- .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
- .ht_supported = true,
- .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
- .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
- .mcs = {
- /* placeholders for now */
- .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
- .rx_highest = 500,
- .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
- }
-};
-
-/*
- * is called in brcms_pci_probe() context, therefore no locking required.
- */
-static int ieee_hw_rate_init(struct ieee80211_hw *hw)
-{
- struct brcms_info *wl = HW_TO_WL(hw);
- int has_5g;
- char phy_list[4];
-
- has_5g = 0;
-
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
- hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
-
- if (brcms_c_get(wl->wlc, BRCM_GET_PHYLIST, (int *)&phy_list) < 0)
- wiphy_err(hw->wiphy, "Phy list failed\n");
-
- if (phy_list[0] == 'n' || phy_list[0] == 'c') {
- if (phy_list[0] == 'c') {
- /* Single stream */
- brcms_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0;
- brcms_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72;
- }
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &brcms_band_2GHz_nphy;
- } else {
- return -EPERM;
- }
-
- /* Assume all bands use the same phy. True for 11n devices. */
- if (NBANDS_PUB(wl->pub) > 1) {
- has_5g++;
- if (phy_list[0] == 'n' || phy_list[0] == 'c') {
- hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
- &brcms_band_5GHz_nphy;
- } else {
- return -EPERM;
- }
- }
- return 0;
-}
-
-/*
- * is called in brcms_pci_probe() context, therefore no locking required.
- */
-static int ieee_hw_init(struct ieee80211_hw *hw)
-{
- hw->flags = IEEE80211_HW_SIGNAL_DBM
- /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */
- | IEEE80211_HW_REPORTS_TX_ACK_STATUS
- | IEEE80211_HW_AMPDU_AGGREGATION;
-
- hw->extra_tx_headroom = brcms_c_get_header_len();
- hw->queues = N_TX_QUEUES;
- hw->max_rates = 2; /* Primary rate and 1 fallback rate */
-
- hw->channel_change_time = 7 * 1000; /* channel change time is dependent on chip and band */
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
-
- hw->rate_control_algorithm = "minstrel_ht";
-
- hw->sta_data_size = sizeof(struct scb);
- return ieee_hw_rate_init(hw);
-}
-
/**
* determines if a device is a WL device, and if so, attaches it.
*
@@ -1154,7 +1180,7 @@ brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
memset(hw->priv, 0, sizeof(*wl));
wl = brcms_attach(pdev->vendor, pdev->device,
- pci_resource_start(pdev, 0), PCI_BUS, pdev,
+ pci_resource_start(pdev, 0), pdev,
pdev->irq);
if (!wl) {
@@ -1171,7 +1197,7 @@ static int brcms_suspend(struct pci_dev *pdev, pm_message_t state)
struct ieee80211_hw *hw;
hw = pci_get_drvdata(pdev);
- wl = HW_TO_WL(hw);
+ wl = hw->priv;
if (!wl) {
wiphy_err(wl->wiphy,
"brcms_suspend: pci_get_drvdata failed\n");
@@ -1179,9 +1205,9 @@ static int brcms_suspend(struct pci_dev *pdev, pm_message_t state)
}
/* only need to flag hw is down for proper resume */
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
wl->pub->hw_up = false;
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
pci_save_state(pdev);
pci_disable_device(pdev);
@@ -1196,7 +1222,7 @@ static int brcms_resume(struct pci_dev *pdev)
u32 val;
hw = pci_get_drvdata(pdev);
- wl = HW_TO_WL(hw);
+ wl = hw->priv;
if (!wl) {
wiphy_err(wl->wiphy,
"wl: brcms_resume: pci_get_drvdata failed\n");
@@ -1226,47 +1252,6 @@ static int brcms_resume(struct pci_dev *pdev)
return err;
}
-/*
-* called from both kernel as from this kernel module.
-* precondition: perimeter lock is not acquired.
-*/
-static void brcms_remove(struct pci_dev *pdev)
-{
- struct brcms_info *wl;
- struct ieee80211_hw *hw;
- int status;
-
- hw = pci_get_drvdata(pdev);
- wl = HW_TO_WL(hw);
- if (!wl) {
- pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
- return;
- }
-
- LOCK(wl);
- status = brcms_c_chipmatch(pdev->vendor, pdev->device);
- UNLOCK(wl);
- if (!status) {
- wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
- "failed\n");
- return;
- }
- if (wl->wlc) {
- wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
- wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
- ieee80211_unregister_hw(hw);
- LOCK(wl);
- brcms_down(wl);
- UNLOCK(wl);
- }
- pci_disable_device(pdev);
-
- brcms_free(wl);
-
- pci_set_drvdata(pdev, NULL);
- ieee80211_free_hw(hw);
-}
-
static struct pci_driver brcms_pci_driver = {
.name = KBUILD_MODNAME,
.probe = brcms_pci_probe,
@@ -1290,8 +1275,6 @@ static int __init brcms_module_init(void)
#ifdef BCMDBG
if (msglevel != 0xdeadbeef)
brcm_msg_level = msglevel;
- if (phymsglevel != 0xdeadbeef)
- phyhal_msg_level = phymsglevel;
#endif /* BCMDBG */
error = pci_register_driver(&brcms_pci_driver);
@@ -1319,82 +1302,6 @@ static void __exit brcms_module_exit(void)
module_init(brcms_module_init);
module_exit(brcms_module_exit);
-/**
- * This function frees the WL per-device resources.
- *
- * This function frees resources owned by the WL device pointed to
- * by the wl parameter.
- *
- * precondition: can both be called locked and unlocked
- *
- */
-static void brcms_free(struct brcms_info *wl)
-{
- struct brcms_timer *t, *next;
-
- /* free ucode data */
- if (wl->fw.fw_cnt)
- brcms_ucode_data_free();
- if (wl->irq)
- free_irq(wl->irq, wl);
-
- /* kill dpc */
- tasklet_kill(&wl->tasklet);
-
- if (wl->pub) {
- brcms_c_module_unregister(wl->pub, "linux", wl);
- }
-
- /* free common resources */
- if (wl->wlc) {
- brcms_c_detach(wl->wlc);
- wl->wlc = NULL;
- wl->pub = NULL;
- }
-
- /* virtual interface deletion is deferred so we cannot spinwait */
-
- /* wait for all pending callbacks to complete */
- while (atomic_read(&wl->callbacks) > 0)
- schedule();
-
- /* free timers */
- for (t = wl->timers; t; t = next) {
- next = t->next;
-#ifdef BCMDBG
- kfree(t->name);
-#endif
- kfree(t);
- }
-
- /*
- * unregister_netdev() calls get_stats() which may read chip registers
- * so we cannot unmap the chip registers until after calling unregister_netdev() .
- */
- if (wl->regsva && wl->bcm_bustype != SDIO_BUS &&
- wl->bcm_bustype != JTAG_BUS) {
- iounmap((void *)wl->regsva);
- }
- wl->regsva = NULL;
-}
-
-/* flags the given rate in rateset as requested */
-static void brcms_set_basic_rate(struct wl_rateset *rs, u16 rate, bool is_br)
-{
- u32 i;
-
- for (i = 0; i < rs->count; i++) {
- if (rate != (rs->rates[i] & 0x7f))
- continue;
-
- if (is_br)
- rs->rates[i] |= BRCMS_RATE_FLAG;
- else
- rs->rates[i] &= BRCMS_RATE_MASK;
- return;
- }
-}
-
/*
* precondition: perimeter lock has been acquired
*/
@@ -1409,7 +1316,7 @@ void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
*/
void brcms_init(struct brcms_info *wl)
{
- BCMMSG(WL_TO_HW(wl)->wiphy, "wl%d\n", wl->pub->unit);
+ BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
brcms_reset(wl);
brcms_c_init(wl->wlc);
@@ -1420,7 +1327,7 @@ void brcms_init(struct brcms_info *wl)
*/
uint brcms_reset(struct brcms_info *wl)
{
- BCMMSG(WL_TO_HW(wl)->wiphy, "wl%d\n", wl->pub->unit);
+ BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
brcms_c_reset(wl->wlc);
/* dpc will not be rescheduled */
@@ -1437,17 +1344,9 @@ void brcms_intrson(struct brcms_info *wl)
{
unsigned long flags;
- INT_LOCK(wl, flags);
+ spin_lock_irqsave(&wl->isr_lock, flags);
brcms_c_intrson(wl->wlc);
- INT_UNLOCK(wl, flags);
-}
-
-/*
- * precondition: perimeter lock has been acquired
- */
-bool wl_alloc_dma_resources(struct brcms_info *wl, uint addrwidth)
-{
- return true;
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
}
u32 brcms_intrsoff(struct brcms_info *wl)
@@ -1455,9 +1354,9 @@ u32 brcms_intrsoff(struct brcms_info *wl)
unsigned long flags;
u32 status;
- INT_LOCK(wl, flags);
+ spin_lock_irqsave(&wl->isr_lock, flags);
status = brcms_c_intrsoff(wl->wlc);
- INT_UNLOCK(wl, flags);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
return status;
}
@@ -1465,9 +1364,9 @@ void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask)
{
unsigned long flags;
- INT_LOCK(wl, flags);
+ spin_lock_irqsave(&wl->isr_lock, flags);
brcms_c_intrsrestore(wl->wlc, macintmask);
- INT_UNLOCK(wl, flags);
+ spin_unlock_irqrestore(&wl->isr_lock, flags);
}
/*
@@ -1497,110 +1396,42 @@ void brcms_down(struct brcms_info *wl)
callbacks = atomic_read(&wl->callbacks) - ret_val;
/* wait for down callbacks to complete */
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
/* For HIGH_only driver, it's important to actually schedule other work,
* not just spin wait since everything runs at schedule level
*/
SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000);
- LOCK(wl);
-}
-
-static irqreturn_t brcms_isr(int irq, void *dev_id)
-{
- struct brcms_info *wl;
- bool ours, wantdpc;
- unsigned long flags;
-
- wl = (struct brcms_info *) dev_id;
-
- ISR_LOCK(wl, flags);
-
- /* call common first level interrupt handler */
- ours = brcms_c_isr(wl->wlc, &wantdpc);
- if (ours) {
- /* if more to do... */
- if (wantdpc) {
-
- /* ...and call the second level interrupt handler */
- /* schedule dpc */
- tasklet_schedule(&wl->tasklet);
- }
- }
-
- ISR_UNLOCK(wl, flags);
-
- return IRQ_RETVAL(ours);
-}
-
-static void brcms_dpc(unsigned long data)
-{
- struct brcms_info *wl;
-
- wl = (struct brcms_info *) data;
-
- LOCK(wl);
-
- /* call the common second level interrupt handler */
- if (wl->pub->up) {
- if (wl->resched) {
- unsigned long flags;
-
- INT_LOCK(wl, flags);
- brcms_c_intrsupd(wl->wlc);
- INT_UNLOCK(wl, flags);
- }
-
- wl->resched = brcms_c_dpc(wl->wlc, true);
- }
-
- /* brcms_c_dpc() may bring the driver down */
- if (!wl->pub->up)
- goto done;
-
- /* re-schedule dpc */
- if (wl->resched)
- tasklet_schedule(&wl->tasklet);
- else {
- /* re-enable interrupts */
- brcms_intrson(wl);
- }
-
- done:
- UNLOCK(wl);
-}
-
-/*
- * is called by the kernel from software irq context
- */
-static void brcms_timer(unsigned long data)
-{
- _brcms_timer((struct brcms_timer *) data);
+ spin_lock_bh(&wl->lock);
}
/*
* precondition: perimeter lock is not acquired
*/
-static void _brcms_timer(struct brcms_timer *t)
+static void _brcms_timer(struct work_struct *work)
{
- LOCK(t->wl);
+ struct brcms_timer *t = container_of(work, struct brcms_timer,
+ dly_wrk.work);
+
+ spin_lock_bh(&t->wl->lock);
if (t->set) {
if (t->periodic) {
- t->timer.expires = jiffies + t->ms * HZ / 1000;
atomic_inc(&t->wl->callbacks);
- add_timer(&t->timer);
- t->set = true;
- } else
+ ieee80211_queue_delayed_work(t->wl->pub->ieee_hw,
+ &t->dly_wrk,
+ msecs_to_jiffies(t->ms));
+ } else {
t->set = false;
+ }
t->fn(t->arg);
}
atomic_dec(&t->wl->callbacks);
- UNLOCK(t->wl);
+ spin_unlock_bh(&t->wl->lock);
}
/*
@@ -1616,15 +1447,10 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
struct brcms_timer *t;
t = kzalloc(sizeof(struct brcms_timer), GFP_ATOMIC);
- if (!t) {
- wiphy_err(wl->wiphy, "wl%d: brcms_init_timer: out of memory\n",
- wl->pub->unit);
- return 0;
- }
+ if (!t)
+ return NULL;
- init_timer(&t->timer);
- t->timer.data = (unsigned long) t;
- t->timer.function = brcms_timer;
+ INIT_DELAYED_WORK(&t->dly_wrk, _brcms_timer);
t->wl = wl;
t->fn = fn;
t->arg = arg;
@@ -1640,27 +1466,28 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
return t;
}
-/* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate
+/*
+ * adds only the kernel timer since it's going to be more accurate
* as well as it's easier to make it periodic
*
* precondition: perimeter lock has been acquired
*/
-void brcms_add_timer(struct brcms_info *wl, struct brcms_timer *t, uint ms,
- int periodic)
+void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)
{
+ struct ieee80211_hw *hw = t->wl->pub->ieee_hw;
+
#ifdef BCMDBG
- if (t->set) {
- wiphy_err(wl->wiphy, "%s: Already set. Name: %s, per %d\n",
+ if (t->set)
+ wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n",
__func__, t->name, periodic);
- }
#endif
t->ms = ms;
t->periodic = (bool) periodic;
t->set = true;
- t->timer.expires = jiffies + ms * HZ / 1000;
- atomic_inc(&wl->callbacks);
- add_timer(&t->timer);
+ atomic_inc(&t->wl->callbacks);
+
+ ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms));
}
/*
@@ -1668,14 +1495,14 @@ void brcms_add_timer(struct brcms_info *wl, struct brcms_timer *t, uint ms,
*
* precondition: perimeter lock has been acquired
*/
-bool brcms_del_timer(struct brcms_info *wl, struct brcms_timer *t)
+bool brcms_del_timer(struct brcms_timer *t)
{
if (t->set) {
t->set = false;
- if (!del_timer(&t->timer)) {
+ if (!cancel_delayed_work(&t->dly_wrk))
return false;
- }
- atomic_dec(&wl->callbacks);
+
+ atomic_dec(&t->wl->callbacks);
}
return true;
@@ -1684,12 +1511,13 @@ bool brcms_del_timer(struct brcms_info *wl, struct brcms_timer *t)
/*
* precondition: perimeter lock has been acquired
*/
-void brcms_free_timer(struct brcms_info *wl, struct brcms_timer *t)
+void brcms_free_timer(struct brcms_timer *t)
{
+ struct brcms_info *wl = t->wl;
struct brcms_timer *tmp;
/* delete the timer in case it is active */
- brcms_del_timer(wl, t);
+ brcms_del_timer(t);
if (wl->timers == t) {
wl->timers = wl->timers->next;
@@ -1717,27 +1545,6 @@ void brcms_free_timer(struct brcms_info *wl, struct brcms_timer *t)
}
/*
- * runs in software irq context
- *
- * precondition: perimeter lock is not acquired
- */
-static int wl_linux_watchdog(void *ctx)
-{
- return 0;
-}
-
-struct firmware_hdr {
- u32 offset;
- u32 len;
- u32 idx;
-};
-
-char *brcms_firmwares[MAX_FW_IMAGES] = {
- "brcm/bcm43xx",
- NULL
-};
-
-/*
* precondition: perimeter lock has been acquired
*/
int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
@@ -1749,15 +1556,15 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;
for (entry = 0; entry < wl->fw.hdr_num_entries[i];
entry++, hdr++) {
- if (hdr->idx == idx) {
- pdata = wl->fw.fw_bin[i]->data + hdr->offset;
- *pbuf = kmalloc(hdr->len, GFP_ATOMIC);
- if (*pbuf == NULL) {
- wiphy_err(wl->wiphy, "fail to alloc %d"
- " bytes\n", hdr->len);
+ u32 len = le32_to_cpu(hdr->len);
+ if (le32_to_cpu(hdr->idx) == idx) {
+ pdata = wl->fw.fw_bin[i]->data +
+ le32_to_cpu(hdr->offset);
+ *pbuf = kmalloc(len, GFP_ATOMIC);
+ if (*pbuf == NULL)
goto fail;
- }
- memcpy(*pbuf, pdata, hdr->len);
+
+ memcpy(*pbuf, pdata, len);
return 0;
}
}
@@ -1773,7 +1580,7 @@ fail:
* Precondition: Since this function is called in brcms_pci_probe() context,
* no locking is required.
*/
-int brcms_ucode_init_uint(struct brcms_info *wl, u32 *data, u32 idx)
+int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
{
int i, entry;
const u8 *pdata;
@@ -1782,14 +1589,15 @@ int brcms_ucode_init_uint(struct brcms_info *wl, u32 *data, u32 idx)
hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;
for (entry = 0; entry < wl->fw.hdr_num_entries[i];
entry++, hdr++) {
- if (hdr->idx == idx) {
- pdata = wl->fw.fw_bin[i]->data + hdr->offset;
- if (hdr->len != 4) {
+ if (le32_to_cpu(hdr->idx) == idx) {
+ pdata = wl->fw.fw_bin[i]->data +
+ le32_to_cpu(hdr->offset);
+ if (le32_to_cpu(hdr->len) != 4) {
wiphy_err(wl->wiphy,
"ERROR: fw hdr len\n");
return -ENOMSG;
}
- *data = *((u32 *) pdata);
+ *n_bytes = le32_to_cpu(*((__le32 *) pdata));
return 0;
}
}
@@ -1799,44 +1607,6 @@ int brcms_ucode_init_uint(struct brcms_info *wl, u32 *data, u32 idx)
}
/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
-{
- int status;
- struct device *device = &pdev->dev;
- char fw_name[100];
- int i;
-
- memset((void *)&wl->fw, 0, sizeof(struct brcms_firmware));
- for (i = 0; i < MAX_FW_IMAGES; i++) {
- if (brcms_firmwares[i] == NULL)
- break;
- sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
- UCODE_LOADER_API_VER);
- status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
- if (status) {
- wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
- KBUILD_MODNAME, fw_name);
- return status;
- }
- sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
- UCODE_LOADER_API_VER);
- status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
- if (status) {
- wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
- KBUILD_MODNAME, fw_name);
- return status;
- }
- wl->fw.hdr_num_entries[i] =
- wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
- }
- wl->fw.fw_cnt = i;
- return brcms_ucode_data_init(wl);
-}
-
-/*
* precondition: can both be called locked and unlocked
*/
void brcms_ucode_free_buf(void *p)
@@ -1845,20 +1615,6 @@ void brcms_ucode_free_buf(void *p)
}
/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static void brcms_release_fw(struct brcms_info *wl)
-{
- int i;
- for (i = 0; i < MAX_FW_IMAGES; i++) {
- release_firmware(wl->fw.fw_bin[i]);
- release_firmware(wl->fw.fw_hdr[i]);
- }
-}
-
-
-/*
* checks validity of all firmware images loaded from user space
*
* Precondition: Since this function is called in brcms_pci_probe() context,
@@ -1895,7 +1651,8 @@ int brcms_check_firmwares(struct brcms_info *wl)
ucode_hdr = (struct firmware_hdr *)fw_hdr->data;
for (entry = 0; entry < wl->fw.hdr_num_entries[i] &&
!rc; entry++, ucode_hdr++) {
- if (ucode_hdr->offset + ucode_hdr->len >
+ if (le32_to_cpu(ucode_hdr->offset) +
+ le32_to_cpu(ucode_hdr->len) >
fw->size) {
wiphy_err(wl->wiphy,
"%s: conflicting bin/hdr\n",
@@ -1920,11 +1677,11 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl)
{
bool blocked = brcms_c_check_radio_disabled(wl->wlc);
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked);
if (blocked)
wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy);
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
return blocked;
}
@@ -1933,7 +1690,7 @@ bool brcms_rfkill_set_hw_state(struct brcms_info *wl)
*/
void brcms_msleep(struct brcms_info *wl, uint ms)
{
- UNLOCK(wl);
+ spin_unlock_bh(&wl->lock);
msleep(ms);
- LOCK(wl);
+ spin_lock_bh(&wl->lock);
}
diff --git a/drivers/staging/brcm80211/brcmsmac/mac80211_if.h b/drivers/staging/brcm80211/brcmsmac/mac80211_if.h
index 3be8655c57e9..177f0e44e4b6 100644
--- a/drivers/staging/brcm80211/brcmsmac/mac80211_if.h
+++ b/drivers/staging/brcm80211/brcmsmac/mac80211_if.h
@@ -19,7 +19,9 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include "ucode_loader.h"
/*
* Starting index for 5G rates in the
* legacy rate table.
@@ -29,20 +31,15 @@
/* softmac ioctl definitions */
#define BRCMS_SET_SHORTSLOT_OVERRIDE 146
-
-/* BMAC Note: High-only driver is no longer working in softirq context as it needs to block and
- * sleep so perimeter lock has to be a semaphore instead of spinlock. This requires timers to be
- * submitted to workqueue instead of being on kernel timer
- */
struct brcms_timer {
- struct timer_list timer;
+ struct delayed_work dly_wrk;
struct brcms_info *wl;
- void (*fn) (void *);
- void *arg; /* argument to fn */
+ void (*fn) (void *); /* function called upon expiration */
+ void *arg; /* fixed argument provided to called function */
uint ms;
bool periodic;
- bool set;
- struct brcms_timer *next;
+ bool set; /* indicates if timer is active */
+ struct brcms_timer *next; /* for freeing on unload */
#ifdef BCMDBG
char *name; /* Description of the timer */
#endif
@@ -63,7 +60,7 @@ struct brcms_firmware {
struct brcms_info {
struct brcms_pub *pub; /* pointer to public wlc state */
- void *wlc; /* pointer to private common os-independent data */
+ struct brcms_c_info *wlc; /* pointer to private common data */
u32 magic;
int irq;
@@ -71,9 +68,8 @@ struct brcms_info {
spinlock_t lock; /* per-device perimeter lock */
spinlock_t isr_lock; /* per-device ISR synchronization lock */
- /* bus type and regsva for unmap in brcms_free() */
- uint bcm_bustype; /* bus type */
- void *regsva; /* opaque chip registers virtual address */
+ /* regsva for unmap in brcms_free() */
+ void __iomem *regsva; /* opaque chip registers virtual address */
/* timer related fields */
atomic_t callbacks; /* # outstanding callback functions */
@@ -81,11 +77,9 @@ struct brcms_info {
struct tasklet_struct tasklet; /* dpc tasklet */
bool resched; /* dpc needs to be and is rescheduled */
-#ifdef LINUXSTA_PS
- u32 pci_psstate[16]; /* pci ps-state save/restore */
-#endif
struct brcms_firmware fw;
struct wiphy *wiphy;
+ struct brcms_ucode ucode;
};
/* misc callbacks */
@@ -98,17 +92,17 @@ extern int brcms_up(struct brcms_info *wl);
extern void brcms_down(struct brcms_info *wl);
extern void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
bool state, int prio);
-extern bool wl_alloc_dma_resources(struct brcms_info *wl, uint dmaddrwidth);
extern bool brcms_rfkill_set_hw_state(struct brcms_info *wl);
/* timer functions */
extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
void (*fn) (void *arg), void *arg,
const char *name);
-extern void brcms_free_timer(struct brcms_info *wl, struct brcms_timer *timer);
-extern void brcms_add_timer(struct brcms_info *wl, struct brcms_timer *timer,
- uint ms, int periodic);
-extern bool brcms_del_timer(struct brcms_info *wl, struct brcms_timer *timer);
+extern void brcms_free_timer(struct brcms_timer *timer);
+extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic);
+extern bool brcms_del_timer(struct brcms_timer *timer);
extern void brcms_msleep(struct brcms_info *wl, uint ms);
+extern void brcms_dpc(unsigned long data);
+extern void brcms_timer(struct brcms_timer *t);
#endif /* _BRCM_MAC80211_IF_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/main.c b/drivers/staging/brcm80211/brcmsmac/main.c
index 96541630aada..510e9bb52287 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.c
+++ b/drivers/staging/brcm80211/brcmsmac/main.c
@@ -15,32 +15,23 @@
*/
#include <linux/pci_ids.h>
+#include <linux/if_ether.h>
#include <net/mac80211.h>
-
#include <brcm_hw_ids.h>
#include <aiutils.h>
+#include <chipcommon.h>
#include "rate.h"
#include "scb.h"
#include "phy/phy_hal.h"
#include "channel.h"
-#include "bmac.h"
#include "antsel.h"
#include "stf.h"
#include "ampdu.h"
-#include "alloc.h"
#include "mac80211_if.h"
+#include "ucode_loader.h"
#include "main.h"
/*
- * WPA(2) definitions
- */
-#define RSN_CAP_4_REPLAY_CNTRS 2
-#define RSN_CAP_16_REPLAY_CNTRS 3
-
-#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS
-#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS
-
-/*
* Indication for txflowcontrol that all priority bits in
* TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
*/
@@ -51,8 +42,10 @@
*/
#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1)
-#define TIMER_INTERVAL_WATCHDOG 1000 /* watchdog timer, in unit of ms */
-#define TIMER_INTERVAL_RADIOCHK 800 /* radio monitor timer, in unit of ms */
+/* watchdog timer, in unit of ms */
+#define TIMER_INTERVAL_WATCHDOG 1000
+/* radio monitor timer, in unit of ms */
+#define TIMER_INTERVAL_RADIOCHK 800
/* Max MPC timeout, in unit of watchdog */
#ifndef BRCMS_MPC_MAX_DELAYCNT
@@ -63,20 +56,19 @@
#define BRCMS_MPC_MIN_DELAYCNT 1
#define BRCMS_MPC_THRESHOLD 3 /* MPC count threshold level */
-#define BEACON_INTERVAL_DEFAULT 100 /* beacon interval, in unit of 1024TU */
-#define DTIM_INTERVAL_DEFAULT 3 /* DTIM interval, in unit of beacon interval */
+/* beacon interval, in unit of 1024TU */
+#define BEACON_INTERVAL_DEFAULT 100
+/* DTIM interval, in unit of beacon interval */
+#define DTIM_INTERVAL_DEFAULT 3
/* Scale down delays to accommodate QT slow speed */
-#define BEACON_INTERVAL_DEF_QT 20 /* beacon interval, in unit of 1024TU */
-#define DTIM_INTERVAL_DEF_QT 1 /* DTIM interval, in unit of beacon interval */
+/* beacon interval, in unit of 1024TU */
+#define BEACON_INTERVAL_DEF_QT 20
+/* DTIM interval, in unit of beacon interval */
+#define DTIM_INTERVAL_DEF_QT 1
#define TBTT_ALIGN_LEEWAY_US 100 /* min leeway before first TBTT in us */
-/* Software feature flag defines used by wlfeatureflag */
-#define WL_SWFL_NOHWRADIO 0x0004
-#define WL_SWFL_FLOWCONTROL 0x0008 /* Enable backpressure to OS stack */
-#define WL_SWFL_WLBSSSORT 0x0010 /* Per-port supports sorting of BSS */
-
/* n-mode support capability */
/* 2x2 includes both 1x1 & 2x2 devices
* reserved #define 2 for future when we want to separate 1x1 & 2x2 and
@@ -160,62 +152,47 @@
#define AC_VI 2
#define AC_VO 3
-/*
- * driver maintains internal 'tick'(wlc->pub->now) which increments in 1s OS timer(soft
- * watchdog) it is not a wall clock and won't increment when driver is in "down" state
- * this low resolution driver tick can be used for maintenance tasks such as phy
- * calibration and scb update
- */
+#define BCN_TMPL_LEN 512 /* length of the BCN template area */
-/* To inform the ucode of the last mcast frame posted so that it can clear moredata bit */
-#define BCMCFID(wlc, fid) brcms_b_write_shm((wlc)->hw, M_BCMC_FID, (fid))
+/* brcms_bss_info flag bit values */
+#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */
-#define BRCMS_WAR16165(wlc) (wlc->pub->sih->bustype == PCI_BUS && \
- (!AP_ENAB(wlc->pub)) && (wlc->war16165))
+/* Flags used in brcms_c_txq_info.stopped */
+/* per prio flow control bits */
+#define TXQ_STOP_FOR_PRIOFC_MASK 0x000000FF
+/* stop txq enqueue for packet drain */
+#define TXQ_STOP_FOR_PKT_DRAIN 0x00000100
+/* stop txq enqueue for ampdu flow control */
+#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL 0x00000200
-/* debug/trace */
-uint brcm_msg_level =
-#if defined(BCMDBG)
- LOG_ERROR_VAL;
-#else
- 0;
-#endif /* BCMDBG */
+#define BRCMS_HWRXOFF 38 /* chip rx buffer offset */
/* Find basic rate for a given rate */
-#define BRCMS_BASIC_RATE(wlc, rspec) (IS_MCS(rspec) ? \
- (wlc)->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK].leg_ofdm] : \
- (wlc)->band->basic_rate[rspec & RSPEC_RATE_MASK])
+static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
+{
+ if (is_mcs_rate(rspec))
+ return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
+ .leg_ofdm];
+ return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
+}
-#define FRAMETYPE(r, mimoframe) (IS_MCS(r) ? mimoframe : (IS_CCK(r) ? FT_CCK : FT_OFDM))
+static u16 frametype(u32 rspec, u8 mimoframe)
+{
+ if (is_mcs_rate(rspec))
+ return mimoframe;
+ return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
+}
-#define RFDISABLE_DEFAULT 10000000 /* rfdisable delay timer 500 ms, runs of ALP clock */
+/* rfdisable delay timer 500 ms, runs of ALP clock */
+#define RFDISABLE_DEFAULT 10000000
#define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */
-#define SCAN_IN_PROGRESS(x) 0
-
-#define EPI_VERSION_NUM 0x054b0b00
-
-#ifdef BCMDBG
-/* pointer to most recently allocated wl/wlc */
-static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
-#endif
-
-const u8 prio2fifo[NUMPRIO] = {
- TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */
- TX_AC_BK_FIFO, /* 1 BK AC_BK Background */
- TX_AC_BK_FIFO, /* 2 -- AC_BK Background */
- TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */
- TX_AC_VI_FIFO, /* 4 CL AC_VI Video */
- TX_AC_VI_FIFO, /* 5 VI AC_VI Video */
- TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */
- TX_AC_VO_FIFO /* 7 NC AC_VO Voice */
-};
-
/* precedences numbers for wlc queues. These are twice as may levels as
* 802.1D priorities.
* Odd numbers are used for HI priority traffic at same precedence levels
- * These constants are used ONLY by wlc_prio2prec_map. Do not use them elsewhere.
+ * These constants are used ONLY by wlc_prio2prec_map. Do not use them
+ * elsewhere.
*/
#define _BRCMS_PREC_NONE 0 /* None = - */
#define _BRCMS_PREC_BK 2 /* BK - Background */
@@ -226,17 +203,182 @@ const u8 prio2fifo[NUMPRIO] = {
#define _BRCMS_PREC_VO 12 /* Vo - Voice */
#define _BRCMS_PREC_NC 14 /* NC - Network Control */
-#define MAXMACLIST 64 /* max # source MAC matches */
-#define BCN_TEMPLATE_COUNT 2
-
/* The BSS is generating beacons in HW */
#define BRCMS_BSSCFG_HW_BCN 0x20
-#define HWBCN_ENAB(cfg) (((cfg)->flags & BRCMS_BSSCFG_HW_BCN) != 0)
+#define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */
+#define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us */
+#define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us */
+#define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */
+
+#define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */
+
+#define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */
+
+/* Per-AC retry limit register definitions; uses defs.h bitfield macros */
+#define EDCF_SHORT_S 0
+#define EDCF_SFB_S 4
+#define EDCF_LONG_S 8
+#define EDCF_LFB_S 12
+#define EDCF_SHORT_M BITFIELD_MASK(4)
+#define EDCF_SFB_M BITFIELD_MASK(4)
+#define EDCF_LONG_M BITFIELD_MASK(4)
+#define EDCF_LFB_M BITFIELD_MASK(4)
+
+#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */
+#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */
+#define RETRY_LONG_DEF 4 /* Default Long retry count */
+#define RETRY_SHORT_FB 3 /* Short count for fallback rate */
+#define RETRY_LONG_FB 2 /* Long count for fallback rate */
+
+#define APHY_CWMIN 15
+#define PHY_CWMAX 1023
+
+#define EDCF_AIFSN_MIN 1
+
+#define FRAGNUM_MASK 0xF
+
+#define APHY_SLOT_TIME 9
+#define BPHY_SLOT_TIME 20
+
+#define WL_SPURAVOID_OFF 0
+#define WL_SPURAVOID_ON1 1
+#define WL_SPURAVOID_ON2 2
+
+/* invalid core flags, use the saved coreflags */
+#define BRCMS_USE_COREFLAGS 0xffffffff
+
+/* values for PLCPHdr_override */
+#define BRCMS_PLCP_AUTO -1
+#define BRCMS_PLCP_SHORT 0
+#define BRCMS_PLCP_LONG 1
+
+/* values for g_protection_override and n_protection_override */
+#define BRCMS_PROTECTION_AUTO -1
+#define BRCMS_PROTECTION_OFF 0
+#define BRCMS_PROTECTION_ON 1
+#define BRCMS_PROTECTION_MMHDR_ONLY 2
+#define BRCMS_PROTECTION_CTS_ONLY 3
+
+/* values for g_protection_control and n_protection_control */
+#define BRCMS_PROTECTION_CTL_OFF 0
+#define BRCMS_PROTECTION_CTL_LOCAL 1
+#define BRCMS_PROTECTION_CTL_OVERLAP 2
+
+/* values for n_protection */
+#define BRCMS_N_PROTECTION_OFF 0
+#define BRCMS_N_PROTECTION_OPTIONAL 1
+#define BRCMS_N_PROTECTION_20IN40 2
+#define BRCMS_N_PROTECTION_MIXEDMODE 3
+
+/* values for band specific 40MHz capabilities */
+#define BRCMS_N_BW_20ALL 0
+#define BRCMS_N_BW_40ALL 1
+#define BRCMS_N_BW_20IN2G_40IN5G 2
+
+/* bitflags for SGI support (sgi_rx iovar) */
+#define BRCMS_N_SGI_20 0x01
+#define BRCMS_N_SGI_40 0x02
+
+/* defines used by the nrate iovar */
+/* MSC in use,indicates b0-6 holds an mcs */
+#define NRATE_MCS_INUSE 0x00000080
+/* rate/mcs value */
+#define NRATE_RATE_MASK 0x0000007f
+/* stf mode mask: siso, cdd, stbc, sdm */
+#define NRATE_STF_MASK 0x0000ff00
+/* stf mode shift */
+#define NRATE_STF_SHIFT 8
+/* bit indicates override both rate & mode */
+#define NRATE_OVERRIDE 0x80000000
+/* bit indicate to override mcs only */
+#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
+#define NRATE_SGI_MASK 0x00800000 /* sgi mode */
+#define NRATE_SGI_SHIFT 23 /* sgi mode */
+#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */
+#define NRATE_LDPC_SHIFT 22 /* ldpc shift */
+
+#define NRATE_STF_SISO 0 /* stf mode SISO */
+#define NRATE_STF_CDD 1 /* stf mode CDD */
+#define NRATE_STF_STBC 2 /* stf mode STBC */
+#define NRATE_STF_SDM 3 /* stf mode SDM */
+
+#define MAX_DMA_SEGS 4
+
+/* Max # of entries in Tx FIFO based on 4kb page size */
+#define NTXD 256
+/* Max # of entries in Rx FIFO based on 4kb page size */
+#define NRXD 256
+
+/* try to keep this # rbufs posted to the chip */
+#define NRXBUFPOST 32
+
+/* data msg txq hiwat mark */
+#define BRCMS_DATAHIWAT 50
+
+/* bounded rx loops */
+#define RXBND 8 /* max # frames to process in brcms_c_recv() */
+#define TXSBND 8 /* max # tx status to process in wlc_txstatus() */
+
+/*
+ * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
+ */
+#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1)
-#define MBSS_BCN_ENAB(cfg) 0
-#define MBSS_PRB_ENAB(cfg) 0
-#define SOFTBCN_ENAB(pub) (0)
+/* brcmu_format_flags() bit description structure */
+struct brcms_c_bit_desc {
+ u32 bit;
+ const char *name;
+};
+
+/*
+ * The following table lists the buffer memory allocated to xmt fifos in HW.
+ * the size is in units of 256bytes(one block), total size is HW dependent
+ * ucode has default fifo partition, sw can overwrite if necessary
+ *
+ * This is documented in twiki under the topic UcodeTxFifo. Please ensure
+ * the twiki is updated before making changes.
+ */
+
+/* Starting corerev for the fifo size table */
+#define XMTFIFOTBL_STARTREV 20
+
+struct d11init {
+ __le16 addr;
+ __le16 size;
+ __le32 value;
+};
+
+struct edcf_acparam {
+ u8 ACI;
+ u8 ECW;
+ u16 TXOP;
+} __packed;
+
+const u8 prio2fifo[NUMPRIO] = {
+ TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */
+ TX_AC_BK_FIFO, /* 1 BK AC_BK Background */
+ TX_AC_BK_FIFO, /* 2 -- AC_BK Background */
+ TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */
+ TX_AC_VI_FIFO, /* 4 CL AC_VI Video */
+ TX_AC_VI_FIFO, /* 5 VI AC_VI Video */
+ TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */
+ TX_AC_VO_FIFO /* 7 NC AC_VO Voice */
+};
+
+/* debug/trace */
+uint brcm_msg_level =
+#if defined(BCMDBG)
+ LOG_ERROR_VAL;
+#else
+ 0;
+#endif /* BCMDBG */
+
+/* TX FIFO number to WME/802.1E Access Category */
+static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
+
+/* WME/802.1E Access Category to TX FIFO number */
+static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
/* 802.1D Priority to precedence queue mapping */
const u8 wlc_prio2prec_map[] = {
@@ -250,26 +392,25 @@ const u8 wlc_prio2prec_map[] = {
_BRCMS_PREC_NC, /* 7 NC - Network Control */
};
-/* Check if a particular BSS config is AP or STA */
-#define BSSCFG_AP(cfg) (0)
-#define BSSCFG_STA(cfg) (1)
-#define BSSCFG_IBSS(cfg) (!(cfg)->BSS)
-
-/* As above for all non-NULL BSS configs */
-#define FOREACH_BSS(wlc, idx, cfg) \
- for (idx = 0; (int) idx < BRCMS_MAXBSSCFG; idx++) \
- if ((cfg = (wlc)->bsscfg[idx]))
-
-/* TX FIFO number to WME/802.1E Access Category */
-const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
-
-/* WME/802.1E Access Category to TX FIFO number */
-static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
-
-static bool in_send_q;
+static const u16 xmtfifo_sz[][NFIFO] = {
+ /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */
+ {20, 192, 192, 21, 17, 5},
+ /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */
+ {9, 58, 22, 14, 14, 5},
+ /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */
+ {20, 192, 192, 21, 17, 5},
+ /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */
+ {20, 192, 192, 21, 17, 5},
+ /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */
+ {9, 58, 22, 14, 14, 5},
+};
-/* Shared memory location index for various AC params */
-#define wme_shmemacindex(ac) wme_ac2fifo[ac]
+static const u8 acbitmap2maxprio[] = {
+ PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
+ PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
+ PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
+ PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
+};
#ifdef BCMDBG
static const char * const fifo_names[] = {
@@ -278,128 +419,2800 @@ static const char * const fifo_names[] = {
static const char fifo_names[6][0];
#endif
-static const u8 acbitmap2maxprio[] = {
- PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
- PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
- PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
- PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
-};
+#ifdef BCMDBG
+/* pointer to most recently allocated wl/wlc */
+static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
+#endif
/* currently the best mechanism for determining SIFS is the band in use */
-#define SIFS(band) ((band)->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME : \
- BPHY_SIFS_TIME);
-
-/* local prototypes */
-static u16 brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc,
- struct ieee80211_hw *hw,
- struct sk_buff *p,
- struct scb *scb, uint frag,
- uint nfrags, uint queue,
- uint next_frag_len,
- struct wsec_key *key,
- ratespec_t rspec_override);
-static void brcms_c_bss_default_init(struct brcms_c_info *wlc);
-static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc);
-static ratespec_t mac80211_wlc_set_nrate(struct brcms_c_info *wlc,
- struct brcms_band *cur_band,
- u32 int_val);
-static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc);
-static void brcms_c_watchdog(void *arg);
-static void brcms_c_watchdog_by_timer(void *arg);
-static u16 brcms_c_rate_shm_offset(struct brcms_c_info *wlc, u8 rate);
-static int brcms_c_set_rateset(struct brcms_c_info *wlc, wlc_rateset_t *rs_arg);
-static u8 brcms_c_local_constraint_qdbm(struct brcms_c_info *wlc);
-
-/* send and receive */
-static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc);
-static void brcms_c_txq_free(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi);
-static void brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi,
- bool on, int prio);
-static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc);
-static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, ratespec_t rate,
- uint length, u8 *plcp);
-static void brcms_c_compute_ofdm_plcp(ratespec_t rate, uint length, u8 *plcp);
-static void brcms_c_compute_mimo_plcp(ratespec_t rate, uint length, u8 *plcp);
-static u16 brcms_c_compute_frame_dur(struct brcms_c_info *wlc, ratespec_t rate,
- u8 preamble_type, uint next_frag_len);
-static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
- struct brcms_d11rxhdr *rxh);
-static void brcms_c_recvctl(struct brcms_c_info *wlc,
- struct d11rxhdr *rxh, struct sk_buff *p);
-static uint brcms_c_calc_frame_len(struct brcms_c_info *wlc, ratespec_t rate,
- u8 preamble_type, uint dur);
-static uint brcms_c_calc_ack_time(struct brcms_c_info *wlc, ratespec_t rate,
- u8 preamble_type);
-static uint brcms_c_calc_cts_time(struct brcms_c_info *wlc, ratespec_t rate,
- u8 preamble_type);
-/* interrupt, up/down, band */
-static void brcms_c_setband(struct brcms_c_info *wlc, uint bandunit);
-static chanspec_t brcms_c_init_chanspec(struct brcms_c_info *wlc);
-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
- chanspec_t chanspec);
-static void brcms_c_bsinit(struct brcms_c_info *wlc);
-static int brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle,
- bool isOFDM, bool writeToShm);
-static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc);
-static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc);
-static void brcms_c_radio_timer(void *arg);
-static void brcms_c_radio_enable(struct brcms_c_info *wlc);
-static void brcms_c_radio_upd(struct brcms_c_info *wlc);
-
-/* scan, association, BSS */
-static uint brcms_c_calc_ba_time(struct brcms_c_info *wlc, ratespec_t rate,
- u8 preamble_type);
-static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap);
-static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val);
-static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val);
-static void brcms_c_war16165(struct brcms_c_info *wlc, bool tx);
-
-static void brcms_c_wme_retries_write(struct brcms_c_info *wlc);
-static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc);
-static uint brcms_c_attach_module(struct brcms_c_info *wlc);
-static void brcms_c_detach_module(struct brcms_c_info *wlc);
-static void brcms_c_timers_deinit(struct brcms_c_info *wlc);
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc);
-static uint brcms_c_down_del_timer(struct brcms_c_info *wlc);
-static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc);
-static int _brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
- struct brcms_c_if *wlcif);
-
-/* conditions under which the PM bit should be set in outgoing frames and STAY_AWAKE is meaningful
+static u16 get_sifs(struct brcms_band *band)
+{
+ return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :
+ BPHY_SIFS_TIME;
+}
+
+/*
+ * Detect Card removed.
+ * Even checking an sbconfig register read will not false trigger when the core
+ * is in reset it breaks CF address mechanism. Accessing gphy phyversion will
+ * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible
+ * reg with fixed 0/1 pattern (some platforms return all 0).
+ * If clocks are present, call the sb routine which will figure out if the
+ * device is removed.
*/
-bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+static bool brcms_deviceremoved(struct brcms_c_info *wlc)
+{
+ if (!wlc->hw->clk)
+ return ai_deviceremoved(wlc->hw->sih);
+ return (R_REG(&wlc->hw->regs->maccontrol) &
+ (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;
+}
+
+/* sum the individual fifo tx pending packet counts */
+static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
+{
+ return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
+ wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
+}
+
+static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
+{
+ return wlc->pub->_nbands > 1 && !wlc->bandlocked;
+}
+
+static int brcms_chspec_bw(u16 chanspec)
+{
+ if (CHSPEC_IS40(chanspec))
+ return BRCMS_40_MHZ;
+ if (CHSPEC_IS20(chanspec))
+ return BRCMS_20_MHZ;
+
+ return BRCMS_10_MHZ;
+}
+
+/*
+ * return true if Minimum Power Consumption should
+ * be entered, false otherwise
+ */
+static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
+{
+ return false;
+}
+
+static bool brcms_c_ismpc(struct brcms_c_info *wlc)
+{
+ return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
+}
+
+static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
+{
+ if (cfg == NULL)
+ return;
+
+ kfree(cfg->current_bss);
+ kfree(cfg);
+}
+
+static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
+{
+ if (wlc == NULL)
+ return;
+
+ brcms_c_bsscfg_mfree(wlc->bsscfg);
+ kfree(wlc->pub);
+ kfree(wlc->modulecb);
+ kfree(wlc->default_bss);
+ kfree(wlc->protection);
+ kfree(wlc->stf);
+ kfree(wlc->bandstate[0]);
+ kfree(wlc->corestate->macstat_snapshot);
+ kfree(wlc->corestate);
+ kfree(wlc->hw->bandstate[0]);
+ kfree(wlc->hw);
+
+ /* free the wlc */
+ kfree(wlc);
+ wlc = NULL;
+}
+
+static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)
{
- int idx;
struct brcms_bss_cfg *cfg;
- /* disallow PS when one of the following global conditions meets */
- if (!wlc->pub->associated)
+ cfg = kzalloc(sizeof(struct brcms_bss_cfg), GFP_ATOMIC);
+ if (cfg == NULL)
+ goto fail;
+
+ cfg->current_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
+ if (cfg->current_bss == NULL)
+ goto fail;
+
+ return cfg;
+
+ fail:
+ brcms_c_bsscfg_mfree(cfg);
+ return NULL;
+}
+
+static struct brcms_c_info *
+brcms_c_attach_malloc(uint unit, uint *err, uint devid)
+{
+ struct brcms_c_info *wlc;
+
+ wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC);
+ if (wlc == NULL) {
+ *err = 1002;
+ goto fail;
+ }
+
+ /* allocate struct brcms_c_pub state structure */
+ wlc->pub = kzalloc(sizeof(struct brcms_pub), GFP_ATOMIC);
+ if (wlc->pub == NULL) {
+ *err = 1003;
+ goto fail;
+ }
+ wlc->pub->wlc = wlc;
+
+ /* allocate struct brcms_hardware state structure */
+
+ wlc->hw = kzalloc(sizeof(struct brcms_hardware), GFP_ATOMIC);
+ if (wlc->hw == NULL) {
+ *err = 1005;
+ goto fail;
+ }
+ wlc->hw->wlc = wlc;
+
+ wlc->hw->bandstate[0] =
+ kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC);
+ if (wlc->hw->bandstate[0] == NULL) {
+ *err = 1006;
+ goto fail;
+ } else {
+ int i;
+
+ for (i = 1; i < MAXBANDS; i++)
+ wlc->hw->bandstate[i] = (struct brcms_hw_band *)
+ ((unsigned long)wlc->hw->bandstate[0] +
+ (sizeof(struct brcms_hw_band) * i));
+ }
+
+ wlc->modulecb =
+ kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC);
+ if (wlc->modulecb == NULL) {
+ *err = 1009;
+ goto fail;
+ }
+
+ wlc->default_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC);
+ if (wlc->default_bss == NULL) {
+ *err = 1010;
+ goto fail;
+ }
+
+ wlc->bsscfg = brcms_c_bsscfg_malloc(unit);
+ if (wlc->bsscfg == NULL) {
+ *err = 1011;
+ goto fail;
+ }
+
+ wlc->protection = kzalloc(sizeof(struct brcms_protection),
+ GFP_ATOMIC);
+ if (wlc->protection == NULL) {
+ *err = 1016;
+ goto fail;
+ }
+
+ wlc->stf = kzalloc(sizeof(struct brcms_stf), GFP_ATOMIC);
+ if (wlc->stf == NULL) {
+ *err = 1017;
+ goto fail;
+ }
+
+ wlc->bandstate[0] =
+ kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC);
+ if (wlc->bandstate[0] == NULL) {
+ *err = 1025;
+ goto fail;
+ } else {
+ int i;
+
+ for (i = 1; i < MAXBANDS; i++)
+ wlc->bandstate[i] = (struct brcms_band *)
+ ((unsigned long)wlc->bandstate[0]
+ + (sizeof(struct brcms_band)*i));
+ }
+
+ wlc->corestate = kzalloc(sizeof(struct brcms_core), GFP_ATOMIC);
+ if (wlc->corestate == NULL) {
+ *err = 1026;
+ goto fail;
+ }
+
+ wlc->corestate->macstat_snapshot =
+ kzalloc(sizeof(struct macstat), GFP_ATOMIC);
+ if (wlc->corestate->macstat_snapshot == NULL) {
+ *err = 1027;
+ goto fail;
+ }
+
+ return wlc;
+
+ fail:
+ brcms_c_detach_mfree(wlc);
+ return NULL;
+}
+
+/*
+ * Update the slot timing for standard 11b/g (20us slots)
+ * or shortslot 11g (9us slots)
+ * The PSM needs to be suspended for this call.
+ */
+static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
+ bool shortslot)
+{
+ struct d11regs __iomem *regs;
+
+ regs = wlc_hw->regs;
+
+ if (shortslot) {
+ /* 11g short slot: 11a timing */
+ W_REG(&regs->ifs_slot, 0x0207); /* APHY_SLOT_TIME */
+ brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);
+ } else {
+ /* 11g long slot: 11b timing */
+ W_REG(&regs->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */
+ brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);
+ }
+}
+
+/*
+ * calculate frame duration of a given rate and length, return
+ * time in usec unit
+ */
+uint
+brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
+ u8 preamble_type, uint mac_len)
+{
+ uint nsyms, dur = 0, Ndps, kNdps;
+ uint rate = rspec2rate(ratespec);
+
+ if (rate == 0) {
+ wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
+ wlc->pub->unit);
+ rate = BRCM_RATE_1M;
+ }
+
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
+ wlc->pub->unit, ratespec, preamble_type, mac_len);
+
+ if (is_mcs_rate(ratespec)) {
+ uint mcs = ratespec & RSPEC_RATE_MASK;
+ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
+
+ dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
+ if (preamble_type == BRCMS_MM_PREAMBLE)
+ dur += PREN_MM_EXT;
+ /* 1000Ndbps = kbps * 4 */
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
+
+ if (rspec_stc(ratespec) == 0)
+ nsyms =
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+ APHY_TAIL_NBITS) * 1000, kNdps);
+ else
+ /* STBC needs to have even number of symbols */
+ nsyms =
+ 2 *
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
+ APHY_TAIL_NBITS) * 1000, 2 * kNdps);
+
+ dur += APHY_SYMBOL_TIME * nsyms;
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ dur += DOT11_OFDM_SIGNAL_EXTENSION;
+ } else if (is_ofdm_rate(rate)) {
+ dur = APHY_PREAMBLE_TIME;
+ dur += APHY_SIGNAL_TIME;
+ /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
+ Ndps = rate * 2;
+ /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
+ nsyms =
+ CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
+ Ndps);
+ dur += APHY_SYMBOL_TIME * nsyms;
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ dur += DOT11_OFDM_SIGNAL_EXTENSION;
+ } else {
+ /*
+ * calc # bits * 2 so factor of 2 in rate (1/2 mbps)
+ * will divide out
+ */
+ mac_len = mac_len * 8 * 2;
+ /* calc ceiling of bits/rate = microseconds of air time */
+ dur = (mac_len + rate - 1) / rate;
+ if (preamble_type & BRCMS_SHORT_PREAMBLE)
+ dur += BPHY_PLCP_SHORT_TIME;
+ else
+ dur += BPHY_PLCP_TIME;
+ }
+ return dur;
+}
+
+static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
+ const struct d11init *inits)
+{
+ int i;
+ u8 __iomem *base;
+ u8 __iomem *addr;
+ u16 size;
+ u32 value;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ base = (u8 __iomem *)wlc_hw->regs;
+
+ for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) {
+ size = le16_to_cpu(inits[i].size);
+ addr = base + le16_to_cpu(inits[i].addr);
+ value = le32_to_cpu(inits[i].value);
+ if (size == 2)
+ W_REG((u16 __iomem *)addr, value);
+ else if (size == 4)
+ W_REG((u32 __iomem *)addr, value);
+ else
+ break;
+ }
+}
+
+static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
+{
+ u8 idx;
+ u16 addr[] = {
+ M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
+ M_HOST_FLAGS5
+ };
+
+ for (idx = 0; idx < MHFMAX; idx++)
+ brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);
+}
+
+static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
+{
+ struct wiphy *wiphy = wlc_hw->wlc->wiphy;
+ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
+
+ /* init microcode host flags */
+ brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);
+
+ /* do band-specific ucode IHR, SHM, and SCR inits */
+ if (D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+ " %d\n", __func__, wlc_hw->unit,
+ wlc_hw->corerev);
+ } else {
+ if (D11REV_IS(wlc_hw->corerev, 24)) {
+ if (BRCMS_ISLCNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw,
+ ucode->d11lcn0bsinitvals24);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in"
+ " core rev %d\n", __func__,
+ wlc_hw->unit, wlc_hw->corerev);
+ } else {
+ wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ }
+ }
+}
+
+static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
+
+ wlc_hw->phyclk = clk;
+
+ if (OFF == clk) { /* clear gmode bit, put phy into reset */
+
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE),
+ (SICF_PRST | SICF_FGC));
+ udelay(1);
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST);
+ udelay(1);
+
+ } else { /* take phy out of reset */
+
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC);
+ udelay(1);
+ ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0);
+ udelay(1);
+
+ }
+}
+
+/* low-level band switch utility routine */
+static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ bandunit);
+
+ wlc_hw->band = wlc_hw->bandstate[bandunit];
+
+ /*
+ * BMAC_NOTE:
+ * until we eliminate need for wlc->band refs in low level code
+ */
+ wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];
+
+ /* set gmode core flag */
+ if (wlc_hw->sbclk && !wlc_hw->noreset)
+ ai_core_cflags(wlc_hw->sih, SICF_GMODE,
+ ((bandunit == 0) ? SICF_GMODE : 0));
+}
+
+/* switch to new band but leave it inactive */
+static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ u32 macintmask;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
+
+ /* disable interrupts */
+ macintmask = brcms_intrsoff(wlc->wl);
+
+ /* radio off */
+ wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
+
+ brcms_b_core_phy_clk(wlc_hw, OFF);
+
+ brcms_c_setxband(wlc_hw, bandunit);
+
+ return macintmask;
+}
+
+/* process an individual struct tx_status */
+static bool
+brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
+{
+ struct sk_buff *p;
+ uint queue;
+ struct d11txh *txh;
+ struct scb *scb = NULL;
+ bool free_pdu;
+ int tx_rts, tx_frame_count, tx_rts_count;
+ uint totlen, supr_status;
+ bool lastframe;
+ struct ieee80211_hdr *h;
+ u16 mcl;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *txrate;
+ int i;
+
+ /* discard intermediate indications for ucode with one legitimate case:
+ * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
+ * but the subsequent tx of DATA failed. so it will start rts/cts
+ * from the beginning (resetting the rts transmission count)
+ */
+ if (!(txs->status & TX_STATUS_AMPDU)
+ && (txs->status & TX_STATUS_INTERMEDIATE)) {
+ wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n",
+ __func__);
return false;
+ }
- /* disallow PS when one of these meets when not scanning */
- if (AP_ACTIVE(wlc) || wlc->monitor)
+ queue = txs->frameid & TXFID_QUEUE_MASK;
+ if (queue >= NFIFO) {
+ p = NULL;
+ goto fatal;
+ }
+
+ p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
+ if (p == NULL)
+ goto fatal;
+
+ txh = (struct d11txh *) (p->data);
+ mcl = le16_to_cpu(txh->MacTxControlLow);
+
+ if (txs->phyerr) {
+ if (brcm_msg_level & LOG_ERROR_VAL) {
+ wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n",
+ txs->phyerr, txh->MainRates);
+ brcms_c_print_txdesc(txh);
+ }
+ brcms_c_print_txstatus(txs);
+ }
+
+ if (txs->frameid != le16_to_cpu(txh->TxFrameID))
+ goto fatal;
+ tx_info = IEEE80211_SKB_CB(p);
+ h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
+
+ if (tx_info->control.sta)
+ scb = &wlc->pri_scb;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
return false;
+ }
+
+ supr_status = txs->status & TX_STATUS_SUPR_MASK;
+ if (supr_status == TX_STATUS_SUPR_BADCH)
+ BCMMSG(wlc->wiphy,
+ "%s: Pkt tx suppressed, possibly channel %d\n",
+ __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec));
+
+ tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS;
+ tx_frame_count =
+ (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;
+ tx_rts_count =
+ (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT;
+
+ lastframe = !ieee80211_has_morefrags(h->frame_control);
+
+ if (!lastframe) {
+ wiphy_err(wlc->wiphy, "Not last frame!\n");
+ } else {
+ /*
+ * Set information to be consumed by Minstrel ht.
+ *
+ * The "fallback limit" is the number of tx attempts a given
+ * MPDU is sent at the "primary" rate. Tx attempts beyond that
+ * limit are sent at the "secondary" rate.
+ * A 'short frame' does not exceed RTS treshold.
+ */
+ u16 sfbl, /* Short Frame Rate Fallback Limit */
+ lfbl, /* Long Frame Rate Fallback Limit */
+ fbl;
- for (idx = 0; idx < BRCMS_MAXBSSCFG; idx++) {
- cfg = wlc->bsscfg[idx];
- if (cfg && BSSCFG_STA(cfg) && cfg->associated) {
+ if (queue < AC_COUNT) {
+ sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
+ EDCF_SFB);
+ lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
+ EDCF_LFB);
+ } else {
+ sfbl = wlc->SFBL;
+ lfbl = wlc->LFBL;
+ }
+
+ txrate = tx_info->status.rates;
+ if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+ fbl = lfbl;
+ else
+ fbl = sfbl;
+
+ ieee80211_tx_info_clear_status(tx_info);
+
+ if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) {
+ /*
+ * rate selection requested a fallback rate
+ * and we used it
+ */
+ txrate[0].count = fbl;
+ txrate[1].count = tx_frame_count - fbl;
+ } else {
+ /*
+ * rate selection did not request fallback rate, or
+ * we didn't need it
+ */
+ txrate[0].count = tx_frame_count;
/*
- * disallow PS when one of the following
- * bsscfg specific conditions meets
+ * rc80211_minstrel.c:minstrel_tx_status() expects
+ * unused rates to be marked with idx = -1
*/
- if (!cfg->BSS || !BRCMS_PORTOPEN(cfg))
- return false;
+ txrate[1].idx = -1;
+ txrate[1].count = 0;
+ }
+
+ /* clear the rest of the rates */
+ for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
+ txrate[i].idx = -1;
+ txrate[i].count = 0;
+ }
+
+ if (txs->status & TX_STATUS_ACK_RCV)
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
- if (!cfg->dtim_programmed)
- return false;
+ totlen = brcmu_pkttotlen(p);
+ free_pdu = true;
+
+ brcms_c_txfifo_complete(wlc, queue, 1);
+
+ if (lastframe) {
+ p->next = NULL;
+ p->prev = NULL;
+ /* remove PLCP & Broadcom tx descriptor header */
+ skb_pull(p, D11_PHY_HDR_LEN);
+ skb_pull(p, D11_TXH_LEN);
+ ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
+ } else {
+ wiphy_err(wlc->wiphy, "%s: Not last frame => not calling "
+ "tx_status\n", __func__);
+ }
+
+ return false;
+
+ fatal:
+ if (p)
+ brcmu_pkt_buf_free_skb(p);
+
+ return true;
+
+}
+
+/* process tx completion events in BMAC
+ * Return true if more tx status need to be processed. false otherwise.
+ */
+static bool
+brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
+{
+ bool morepending = false;
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+ struct d11regs __iomem *regs;
+ struct tx_status txstatus, *txs;
+ u32 s1, s2;
+ uint n = 0;
+ /*
+ * Param 'max_tx_num' indicates max. # tx status to process before
+ * break out.
+ */
+ uint max_tx_num = bound ? TXSBND : -1;
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ txs = &txstatus;
+ regs = wlc_hw->regs;
+ *fatal = false;
+ while (!(*fatal)
+ && (s1 = R_REG(&regs->frmtxstatus)) & TXS_V) {
+
+ if (s1 == 0xffffffff) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
+ wlc_hw->unit, __func__);
+ return morepending;
}
+
+ s2 = R_REG(&regs->frmtxstatus2);
+
+ txs->status = s1 & TXS_STATUS_MASK;
+ txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
+ txs->sequence = s2 & TXS_SEQ_MASK;
+ txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
+ txs->lasttxtime = 0;
+
+ *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);
+
+ /* !give others some time to run! */
+ if (++n >= max_tx_num)
+ break;
}
+ if (*fatal)
+ return 0;
+
+ if (n >= max_tx_num)
+ morepending = true;
+
+ if (!pktq_empty(&wlc->pkt_queue->q))
+ brcms_c_send_q(wlc);
+
+ return morepending;
+}
+
+static void brcms_c_tbtt(struct brcms_c_info *wlc)
+{
+ if (!wlc->bsscfg->BSS)
+ /*
+ * DirFrmQ is now valid...defer setting until end
+ * of ATIM window
+ */
+ wlc->qvalid |= MCMD_DIRFRMQVAL;
+}
+
+/* set initial host flags value */
+static void
+brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+
+ memset(mhfs, 0, MHFMAX * sizeof(u16));
+
+ mhfs[MHF2] |= mhf2_init;
+
+ /* prohibit use of slowclock on multifunction boards */
+ if (wlc_hw->boardflags & BFL_NOPLLDOWN)
+ mhfs[MHF1] |= MHF1_FORCEFASTCLK;
+
+ if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {
+ mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;
+ mhfs[MHF1] |= MHF1_IQSWAP_WAR;
+ }
+}
+
+static struct dma64regs __iomem *
+dmareg(struct brcms_hardware *hw, uint direction, uint fifonum)
+{
+ if (direction == DMA_TX)
+ return &(hw->regs->fifo64regs[fifonum].dmaxmt);
+ return &(hw->regs->fifo64regs[fifonum].dmarcv);
+}
+
+static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
+{
+ uint i;
+ char name[8];
+ /*
+ * ucode host flag 2 needed for pio mode, independent of band and fifo
+ */
+ u16 pio_mhf2 = 0;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ uint unit = wlc_hw->unit;
+ struct wiphy *wiphy = wlc->wiphy;
+
+ /* name and offsets for dma_attach */
+ snprintf(name, sizeof(name), "wl%d", unit);
+
+ if (wlc_hw->di[0] == NULL) { /* Init FIFOs */
+ int dma_attach_err = 0;
+
+ /*
+ * FIFO 0
+ * TX: TX_AC_BK_FIFO (TX AC Background data packets)
+ * RX: RX_FIFO (RX data packets)
+ */
+ wlc_hw->di[0] = dma_attach(name, wlc_hw->sih,
+ (wme ? dmareg(wlc_hw, DMA_TX, 0) :
+ NULL), dmareg(wlc_hw, DMA_RX, 0),
+ (wme ? NTXD : 0), NRXD,
+ RXBUFSZ, -1, NRXBUFPOST,
+ BRCMS_HWRXOFF, &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[0]);
+
+ /*
+ * FIFO 1
+ * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)
+ * (legacy) TX_DATA_FIFO (TX data packets)
+ * RX: UNUSED
+ */
+ wlc_hw->di[1] = dma_attach(name, wlc_hw->sih,
+ dmareg(wlc_hw, DMA_TX, 1), NULL,
+ NTXD, 0, 0, -1, 0, 0,
+ &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[1]);
+
+ /*
+ * FIFO 2
+ * TX: TX_AC_VI_FIFO (TX AC Video data packets)
+ * RX: UNUSED
+ */
+ wlc_hw->di[2] = dma_attach(name, wlc_hw->sih,
+ dmareg(wlc_hw, DMA_TX, 2), NULL,
+ NTXD, 0, 0, -1, 0, 0,
+ &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[2]);
+ /*
+ * FIFO 3
+ * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
+ * (legacy) TX_CTL_FIFO (TX control & mgmt packets)
+ */
+ wlc_hw->di[3] = dma_attach(name, wlc_hw->sih,
+ dmareg(wlc_hw, DMA_TX, 3),
+ NULL, NTXD, 0, 0, -1,
+ 0, 0, &brcm_msg_level);
+ dma_attach_err |= (NULL == wlc_hw->di[3]);
+/* Cleaner to leave this as if with AP defined */
+
+ if (dma_attach_err) {
+ wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed"
+ "\n", unit);
+ return false;
+ }
+
+ /* get pointer to dma engine tx flow control variable */
+ for (i = 0; i < NFIFO; i++)
+ if (wlc_hw->di[i])
+ wlc_hw->txavail[i] =
+ (uint *) dma_getvar(wlc_hw->di[i],
+ "&txavail");
+ }
+
+ /* initial ucode host flags */
+ brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);
+
return true;
}
+static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)
+{
+ uint j;
+
+ for (j = 0; j < NFIFO; j++) {
+ if (wlc_hw->di[j]) {
+ dma_detach(wlc_hw->di[j]);
+ wlc_hw->di[j] = NULL;
+ }
+ }
+}
+
+/*
+ * Initialize brcms_c_info default values ...
+ * may get overrides later in this function
+ * BMAC_NOTES, move low out and resolve the dangling ones
+ */
+static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
+{
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+
+ /* set default sw macintmask value */
+ wlc->defmacintmask = DEF_MACINTMASK;
+
+ /* various 802.11g modes */
+ wlc_hw->shortslot = false;
+
+ wlc_hw->SFBL = RETRY_SHORT_FB;
+ wlc_hw->LFBL = RETRY_LONG_FB;
+
+ /* default mac retry limits */
+ wlc_hw->SRL = RETRY_SHORT_DEF;
+ wlc_hw->LRL = RETRY_LONG_DEF;
+ wlc_hw->chanspec = ch20mhz_chspec(1);
+}
+
+static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
+{
+ /* delay before first read of ucode state */
+ udelay(40);
+
+ /* wait until ucode is no longer asleep */
+ SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
+ DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
+}
+
+/* control chip clock to save power, enable dynamic clock or force fast clock */
+static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
+{
+ if (wlc_hw->sih->cccaps & CC_CAP_PMU) {
+ /* new chips with PMU, CCS_FORCEHT will distribute the HT clock
+ * on backplane, but mac core will still run on ALP(not HT) when
+ * it enters powersave mode, which means the FCA bit may not be
+ * set. Should wakeup mac if driver wants it to run on HT.
+ */
+
+ if (wlc_hw->clk) {
+ if (mode == CLK_FAST) {
+ OR_REG(&wlc_hw->regs->clk_ctl_st,
+ CCS_FORCEHT);
+
+ udelay(64);
+
+ SPINWAIT(((R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & CCS_HTAVAIL) == 0),
+ PMU_MAX_TRANSITION_DLY);
+ WARN_ON(!(R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & CCS_HTAVAIL));
+ } else {
+ if ((wlc_hw->sih->pmurev == 0) &&
+ (R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ)))
+ SPINWAIT(((R_REG
+ (&wlc_hw->regs->
+ clk_ctl_st) & CCS_HTAVAIL)
+ == 0),
+ PMU_MAX_TRANSITION_DLY);
+ AND_REG(&wlc_hw->regs->clk_ctl_st,
+ ~CCS_FORCEHT);
+ }
+ }
+ wlc_hw->forcefastclk = (mode == CLK_FAST);
+ } else {
+
+ /* old chips w/o PMU, force HT through cc,
+ * then use FCA to verify mac is running fast clock
+ */
+
+ wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode);
+
+ /* check fast clock is available (if core is not in reset) */
+ if (wlc_hw->forcefastclk && wlc_hw->clk)
+ WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) &
+ SISF_FCLKA));
+
+ /*
+ * keep the ucode wake bit on if forcefastclk is on since we
+ * do not want ucode to put us back to slow clock when it dozes
+ * for PM mode. Code below matches the wake override bit with
+ * current forcefastclk state. Only setting bit in wake_override
+ * instead of waking ucode immediately since old code had this
+ * behavior. Older code set wlc->forcefastclk but only had the
+ * wake happen if the wakup_ucode work (protected by an up
+ * check) was executed just below.
+ */
+ if (wlc_hw->forcefastclk)
+ mboolset(wlc_hw->wake_override,
+ BRCMS_WAKE_OVERRIDE_FORCEFAST);
+ else
+ mboolclr(wlc_hw->wake_override,
+ BRCMS_WAKE_OVERRIDE_FORCEFAST);
+ }
+}
+
+/* set or clear ucode host flag bits
+ * it has an optimization for no-change write
+ * it only writes through shared memory when the core has clock;
+ * pre-CLK changes should use wlc_write_mhf to get around the optimization
+ *
+ *
+ * bands values are: BRCM_BAND_AUTO <--- Current band only
+ * BRCM_BAND_5G <--- 5G band only
+ * BRCM_BAND_2G <--- 2G band only
+ * BRCM_BAND_ALL <--- All bands
+ */
+void
+brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
+ int bands)
+{
+ u16 save;
+ u16 addr[MHFMAX] = {
+ M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,
+ M_HOST_FLAGS5
+ };
+ struct brcms_hw_band *band;
+
+ if ((val & ~mask) || idx >= MHFMAX)
+ return; /* error condition */
+
+ switch (bands) {
+ /* Current band only or all bands,
+ * then set the band to current band
+ */
+ case BRCM_BAND_AUTO:
+ case BRCM_BAND_ALL:
+ band = wlc_hw->band;
+ break;
+ case BRCM_BAND_5G:
+ band = wlc_hw->bandstate[BAND_5G_INDEX];
+ break;
+ case BRCM_BAND_2G:
+ band = wlc_hw->bandstate[BAND_2G_INDEX];
+ break;
+ default:
+ band = NULL; /* error condition */
+ }
+
+ if (band) {
+ save = band->mhfs[idx];
+ band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;
+
+ /* optimization: only write through if changed, and
+ * changed band is the current band
+ */
+ if (wlc_hw->clk && (band->mhfs[idx] != save)
+ && (band == wlc_hw->band))
+ brcms_b_write_shm(wlc_hw, addr[idx],
+ (u16) band->mhfs[idx]);
+ }
+
+ if (bands == BRCM_BAND_ALL) {
+ wlc_hw->bandstate[0]->mhfs[idx] =
+ (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;
+ wlc_hw->bandstate[1]->mhfs[idx] =
+ (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;
+ }
+}
+
+/* set the maccontrol register to desired reset state and
+ * initialize the sw cache of the register
+ */
+static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)
+{
+ /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */
+ wlc_hw->maccontrol = 0;
+ wlc_hw->suspended_fifos = 0;
+ wlc_hw->wake_override = 0;
+ wlc_hw->mute_override = 0;
+ brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);
+}
+
+/*
+ * write the software state of maccontrol and
+ * overrides to the maccontrol register
+ */
+static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)
+{
+ u32 maccontrol = wlc_hw->maccontrol;
+
+ /* OR in the wake bit if overridden */
+ if (wlc_hw->wake_override)
+ maccontrol |= MCTL_WAKE;
+
+ /* set AP and INFRA bits for mute if needed */
+ if (wlc_hw->mute_override) {
+ maccontrol &= ~(MCTL_AP);
+ maccontrol |= MCTL_INFRA;
+ }
+
+ W_REG(&wlc_hw->regs->maccontrol, maccontrol);
+}
+
+/* set or clear maccontrol bits */
+void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)
+{
+ u32 maccontrol;
+ u32 new_maccontrol;
+
+ if (val & ~mask)
+ return; /* error condition */
+ maccontrol = wlc_hw->maccontrol;
+ new_maccontrol = (maccontrol & ~mask) | val;
+
+ /* if the new maccontrol value is the same as the old, nothing to do */
+ if (new_maccontrol == maccontrol)
+ return;
+
+ /* something changed, cache the new value */
+ wlc_hw->maccontrol = new_maccontrol;
+
+ /* write the new values with overrides applied */
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
+ u32 override_bit)
+{
+ if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {
+ mboolset(wlc_hw->wake_override, override_bit);
+ return;
+ }
+
+ mboolset(wlc_hw->wake_override, override_bit);
+
+ brcms_c_mctrl_write(wlc_hw);
+ brcms_b_wait_for_wake(wlc_hw);
+}
+
+void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
+ u32 override_bit)
+{
+ mboolclr(wlc_hw->wake_override, override_bit);
+
+ if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))
+ return;
+
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+/* When driver needs ucode to stop beaconing, it has to make sure that
+ * MCTL_AP is clear and MCTL_INFRA is set
+ * Mode MCTL_AP MCTL_INFRA
+ * AP 1 1
+ * STA 0 1 <--- This will ensure no beacons
+ * IBSS 0 0
+ */
+static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw)
+{
+ wlc_hw->mute_override = 1;
+
+ /* if maccontrol already has AP == 0 and INFRA == 1 without this
+ * override, then there is no change to write
+ */
+ if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
+ return;
+
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+/* Clear the override on AP and INFRA bits */
+static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw)
+{
+ if (wlc_hw->mute_override == 0)
+ return;
+
+ wlc_hw->mute_override = 0;
+
+ /* if maccontrol already has AP == 0 and INFRA == 1 without this
+ * override, then there is no change to write
+ */
+ if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)
+ return;
+
+ brcms_c_mctrl_write(wlc_hw);
+}
+
+/*
+ * Write a MAC address to the given match reg offset in the RXE match engine.
+ */
+static void
+brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,
+ const u8 *addr)
+{
+ struct d11regs __iomem *regs;
+ u16 mac_l;
+ u16 mac_m;
+ u16 mac_h;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n",
+ wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+ mac_l = addr[0] | (addr[1] << 8);
+ mac_m = addr[2] | (addr[3] << 8);
+ mac_h = addr[4] | (addr[5] << 8);
+
+ /* enter the MAC addr into the RXE match registers */
+ W_REG(&regs->rcm_ctl, RCM_INC_DATA | match_reg_offset);
+ W_REG(&regs->rcm_mat_data, mac_l);
+ W_REG(&regs->rcm_mat_data, mac_m);
+ W_REG(&regs->rcm_mat_data, mac_h);
+
+}
+
+void
+brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,
+ void *buf)
+{
+ struct d11regs __iomem *regs;
+ u32 word;
+ __le32 word_le;
+ __be32 word_be;
+ bool be_bit;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+ W_REG(&regs->tplatewrptr, offset);
+
+ /* if MCTL_BIGEND bit set in mac control register,
+ * the chip swaps data in fifo, as well as data in
+ * template ram
+ */
+ be_bit = (R_REG(&regs->maccontrol) & MCTL_BIGEND) != 0;
+
+ while (len > 0) {
+ memcpy(&word, buf, sizeof(u32));
+
+ if (be_bit) {
+ word_be = cpu_to_be32(word);
+ word = *(u32 *)&word_be;
+ } else {
+ word_le = cpu_to_le32(word);
+ word = *(u32 *)&word_le;
+ }
+
+ W_REG(&regs->tplatewrdata, word);
+
+ buf = (u8 *) buf + sizeof(u32);
+ len -= sizeof(u32);
+ }
+}
+
+static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin)
+{
+ wlc_hw->band->CWmin = newmin;
+
+ W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, newmin);
+}
+
+static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax)
+{
+ wlc_hw->band->CWmax = newmax;
+
+ W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, newmax);
+}
+
+void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
+{
+ bool fastclk;
+
+ /* request FAST clock if not on */
+ fastclk = wlc_hw->forcefastclk;
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
+
+ brcms_b_phy_reset(wlc_hw);
+ wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));
+
+ /* restore the clk */
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+}
+
+static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
+{
+ u16 v;
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+ /* update SYNTHPU_DLY */
+
+ if (BRCMS_ISLCNPHY(wlc->band))
+ v = SYNTHPU_DLY_LPPHY_US;
+ else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3)))
+ v = SYNTHPU_DLY_NPHY_US;
+ else
+ v = SYNTHPU_DLY_BPHY_US;
+
+ brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);
+}
+
+static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)
+{
+ u16 phyctl;
+ u16 phytxant = wlc_hw->bmac_phytxant;
+ u16 mask = PHY_TXC_ANT_MASK;
+
+ /* set the Probe Response frame phy control word */
+ phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);
+ phyctl = (phyctl & ~mask) | phytxant;
+ brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);
+
+ /* set the Response (ACK/CTS) frame phy control word */
+ phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);
+ phyctl = (phyctl & ~mask) | phytxant;
+ brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);
+}
+
+static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,
+ u8 rate)
+{
+ uint i;
+ u8 plcp_rate = 0;
+ struct plcp_signal_rate_lookup {
+ u8 rate;
+ u8 signal_rate;
+ };
+ /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */
+ const struct plcp_signal_rate_lookup rate_lookup[] = {
+ {BRCM_RATE_6M, 0xB},
+ {BRCM_RATE_9M, 0xF},
+ {BRCM_RATE_12M, 0xA},
+ {BRCM_RATE_18M, 0xE},
+ {BRCM_RATE_24M, 0x9},
+ {BRCM_RATE_36M, 0xD},
+ {BRCM_RATE_48M, 0x8},
+ {BRCM_RATE_54M, 0xC}
+ };
+
+ for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {
+ if (rate == rate_lookup[i].rate) {
+ plcp_rate = rate_lookup[i].signal_rate;
+ break;
+ }
+ }
+
+ /* Find the SHM pointer to the rate table entry by looking in the
+ * Direct-map Table
+ */
+ return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));
+}
+
+static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)
+{
+ u8 rate;
+ u8 rates[8] = {
+ BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,
+ BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M
+ };
+ u16 entry_ptr;
+ u16 pctl1;
+ uint i;
+
+ if (!BRCMS_PHY_11N_CAP(wlc_hw->band))
+ return;
+
+ /* walk the phy rate table and update the entries */
+ for (i = 0; i < ARRAY_SIZE(rates); i++) {
+ rate = rates[i];
+
+ entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);
+
+ /* read the SHM Rate Table entry OFDM PCTL1 values */
+ pctl1 =
+ brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);
+
+ /* modify the value */
+ pctl1 &= ~PHY_TXC1_MODE_MASK;
+ pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);
+
+ /* Update the SHM Rate Table entry OFDM PCTL1 values */
+ brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,
+ pctl1);
+ }
+}
+
+/* band-specific init */
+static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ wlc_hw->band->bandunit);
+
+ brcms_c_ucode_bsinit(wlc_hw);
+
+ wlc_phy_init(wlc_hw->band->pi, chanspec);
+
+ brcms_c_ucode_txant_set(wlc_hw);
+
+ /*
+ * cwmin is band-specific, update hardware
+ * with value for current band
+ */
+ brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);
+ brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);
+
+ brcms_b_update_slot_timing(wlc_hw,
+ wlc_hw->band->bandtype == BRCM_BAND_5G ?
+ true : wlc_hw->shortslot);
+
+ /* write phytype and phyvers */
+ brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);
+ brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);
+
+ /*
+ * initialize the txphyctl1 rate table since
+ * shmem is shared between bands
+ */
+ brcms_upd_ofdm_pctl1_table(wlc_hw);
+
+ brcms_b_upd_synthpu(wlc_hw);
+}
+
+/* Perform a soft reset of the PHY PLL */
+void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_addr), ~0, 0);
+ udelay(1);
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), 0x4, 0);
+ udelay(1);
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), 0x4, 4);
+ udelay(1);
+ ai_corereg(wlc_hw->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol_data), 0x4, 0);
+ udelay(1);
+}
+
+/* light way to turn on phy clock without reset for NPHY only
+ * refer to brcms_b_core_phy_clk for full version
+ */
+void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk)
+{
+ /* support(necessary for NPHY and HYPHY) only */
+ if (!BRCMS_ISNPHY(wlc_hw->band))
+ return;
+
+ if (ON == clk)
+ ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC);
+ else
+ ai_core_cflags(wlc_hw->sih, SICF_FGC, 0);
+
+}
+
+void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk)
+{
+ if (ON == clk)
+ ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE);
+ else
+ ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0);
+}
+
+void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)
+{
+ struct brcms_phy_pub *pih = wlc_hw->band->pi;
+ u32 phy_bw_clkbits;
+ bool phy_in_reset = false;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (pih == NULL)
+ return;
+
+ phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);
+
+ /* Specific reset sequence required for NPHY rev 3 and 4 */
+ if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&
+ NREV_LE(wlc_hw->band->phyrev, 4)) {
+ /* Set the PHY bandwidth */
+ ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits);
+
+ udelay(1);
+
+ /* Perform a soft reset of the PHY PLL */
+ brcms_b_core_phypll_reset(wlc_hw);
+
+ /* reset the PHY */
+ ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE),
+ (SICF_PRST | SICF_PCLKE));
+ phy_in_reset = true;
+ } else {
+ ai_core_cflags(wlc_hw->sih,
+ (SICF_PRST | SICF_PCLKE | SICF_BWMASK),
+ (SICF_PRST | SICF_PCLKE | phy_bw_clkbits));
+ }
+
+ udelay(2);
+ brcms_b_core_phy_clk(wlc_hw, ON);
+
+ if (pih)
+ wlc_phy_anacore(pih, ON);
+}
+
+/* switch to and initialize new band */
+static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,
+ u16 chanspec) {
+ struct brcms_c_info *wlc = wlc_hw->wlc;
+ u32 macintmask;
+
+ /* Enable the d11 core before accessing it */
+ if (!ai_iscoreup(wlc_hw->sih)) {
+ ai_core_reset(wlc_hw->sih, 0, 0);
+ brcms_c_mctrl_reset(wlc_hw);
+ }
+
+ macintmask = brcms_c_setband_inact(wlc, bandunit);
+
+ if (!wlc_hw->up)
+ return;
+
+ brcms_b_core_phy_clk(wlc_hw, ON);
+
+ /* band-specific initializations */
+ brcms_b_bsinit(wlc, chanspec);
+
+ /*
+ * If there are any pending software interrupt bits,
+ * then replace these with a harmless nonzero value
+ * so brcms_c_dpc() will re-enable interrupts when done.
+ */
+ if (wlc->macintstatus)
+ wlc->macintstatus = MI_DMAINT;
+
+ /* restore macintmask */
+ brcms_intrsrestore(wlc->wl, macintmask);
+
+ /* ucode should still be suspended.. */
+ WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0);
+}
+
+static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)
+{
+
+ /* reject unsupported corerev */
+ if (!CONF_HAS(D11CONF, wlc_hw->corerev)) {
+ wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n",
+ wlc_hw->corerev);
+ return false;
+ }
+
+ return true;
+}
+
+/* Validate some board info parameters */
+static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
+{
+ uint boardrev = wlc_hw->boardrev;
+
+ /* 4 bits each for board type, major, minor, and tiny version */
+ uint brt = (boardrev & 0xf000) >> 12;
+ uint b0 = (boardrev & 0xf00) >> 8;
+ uint b1 = (boardrev & 0xf0) >> 4;
+ uint b2 = boardrev & 0xf;
+
+ /* voards from other vendors are always considered valid */
+ if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM)
+ return true;
+
+ /* do some boardrev sanity checks when boardvendor is Broadcom */
+ if (boardrev == 0)
+ return false;
+
+ if (boardrev <= 0xff)
+ return true;
+
+ if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)
+ || (b2 > 9))
+ return false;
+
+ return true;
+}
+
+static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
+{
+ enum brcms_srom_id var_id = BRCMS_SROM_MACADDR;
+ char *macaddr;
+
+ /* If macaddr exists, use it (Sromrev4, CIS, ...). */
+ macaddr = getvar(wlc_hw->sih, var_id);
+ if (macaddr != NULL)
+ return macaddr;
+
+ if (wlc_hw->_nbands > 1)
+ var_id = BRCMS_SROM_ET1MACADDR;
+ else
+ var_id = BRCMS_SROM_IL0MACADDR;
+
+ macaddr = getvar(wlc_hw->sih, var_id);
+ if (macaddr == NULL)
+ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
+ "getvar(%d) not found\n", wlc_hw->unit, var_id);
+
+ return macaddr;
+}
+
+/* power both the pll and external oscillator on/off */
+static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
+
+ /*
+ * dont power down if plldown is false or
+ * we must poll hw radio disable
+ */
+ if (!want && wlc_hw->pllreq)
+ return;
+
+ if (wlc_hw->sih)
+ ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
+
+ wlc_hw->sbclk = want;
+ if (!wlc_hw->sbclk) {
+ wlc_hw->clk = false;
+ if (wlc_hw->band && wlc_hw->band->pi)
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+ }
+}
+
+/*
+ * Return true if radio is disabled, otherwise false.
+ * hw radio disable signal is an external pin, users activate it asynchronously
+ * this function could be called when driver is down and w/o clock
+ * it operates on different registers depending on corerev and boardflag.
+ */
+static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)
+{
+ bool v, clk, xtal;
+ u32 resetbits = 0, flags = 0;
+
+ xtal = wlc_hw->sbclk;
+ if (!xtal)
+ brcms_b_xtal(wlc_hw, ON);
+
+ /* may need to take core out of reset first */
+ clk = wlc_hw->clk;
+ if (!clk) {
+ /*
+ * mac no longer enables phyclk automatically when driver
+ * accesses phyreg throughput mac. This can be skipped since
+ * only mac reg is accessed below
+ */
+ flags |= SICF_PCLKE;
+
+ /*
+ * AI chip doesn't restore bar0win2 on
+ * hibernation/resume, need sw fixup
+ */
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID))
+ wlc_hw->regs = (struct d11regs __iomem *)
+ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
+ ai_core_reset(wlc_hw->sih, flags, resetbits);
+ brcms_c_mctrl_reset(wlc_hw);
+ }
+
+ v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0);
+
+ /* put core back into reset */
+ if (!clk)
+ ai_core_disable(wlc_hw->sih, 0);
+
+ if (!xtal)
+ brcms_b_xtal(wlc_hw, OFF);
+
+ return v;
+}
+
+static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)
+{
+ struct dma_pub *di = wlc_hw->di[fifo];
+ return dma_rxreset(di);
+}
+
+/* d11 core reset
+ * ensure fask clock during reset
+ * reset dma
+ * reset d11(out of reset)
+ * reset phy(out of reset)
+ * clear software macintstatus for fresh new start
+ * one testing hack wlc_hw->noreset will bypass the d11/phy reset
+ */
+void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
+{
+ struct d11regs __iomem *regs;
+ uint i;
+ bool fastclk;
+ u32 resetbits = 0;
+
+ if (flags == BRCMS_USE_COREFLAGS)
+ flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+
+ /* request FAST clock if not on */
+ fastclk = wlc_hw->forcefastclk;
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ /* reset the dma engines except first time thru */
+ if (ai_iscoreup(wlc_hw->sih)) {
+ for (i = 0; i < NFIFO; i++)
+ if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i])))
+ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: "
+ "dma_txreset[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, i);
+
+ if ((wlc_hw->di[RX_FIFO])
+ && (!wlc_dma_rxreset(wlc_hw, RX_FIFO)))
+ wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset"
+ "[%d]: cannot stop dma\n",
+ wlc_hw->unit, __func__, RX_FIFO);
+ }
+ /* if noreset, just stop the psm and return */
+ if (wlc_hw->noreset) {
+ wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */
+ brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);
+ return;
+ }
+
+ /*
+ * mac no longer enables phyclk automatically when driver accesses
+ * phyreg throughput mac, AND phy_reset is skipped at early stage when
+ * band->pi is invalid. need to enable PHY CLK
+ */
+ flags |= SICF_PCLKE;
+
+ /*
+ * reset the core
+ * In chips with PMU, the fastclk request goes through d11 core
+ * reg 0x1e0, which is cleared by the core_reset. have to re-request it.
+ *
+ * This adds some delay and we can optimize it by also requesting
+ * fastclk through chipcommon during this period if necessary. But
+ * that has to work coordinate with other driver like mips/arm since
+ * they may touch chipcommon as well.
+ */
+ wlc_hw->clk = false;
+ ai_core_reset(wlc_hw->sih, flags, resetbits);
+ wlc_hw->clk = true;
+ if (wlc_hw->band && wlc_hw->band->pi)
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);
+
+ brcms_c_mctrl_reset(wlc_hw);
+
+ if (wlc_hw->sih->cccaps & CC_CAP_PMU)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ brcms_b_phy_reset(wlc_hw);
+
+ /* turn on PHY_PLL */
+ brcms_b_core_phypll_ctl(wlc_hw, true);
+
+ /* clear sw intstatus */
+ wlc_hw->wlc->macintstatus = 0;
+
+ /* restore the clk setting */
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+}
+
+/* txfifo sizes needs to be modified(increased) since the newer cores
+ * have more memory.
+ */
+static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u16 fifo_nu;
+ u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;
+ u16 txfifo_def, txfifo_def1;
+ u16 txfifo_cmd;
+
+ /* tx fifos start at TXFIFO_START_BLK from the Base address */
+ txfifo_startblk = TXFIFO_START_BLK;
+
+ /* sequence of operations: reset fifo, set fifo size, reset fifo */
+ for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
+
+ txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
+ txfifo_def = (txfifo_startblk & 0xff) |
+ (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
+ txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
+ ((((txfifo_endblk -
+ 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
+ txfifo_cmd =
+ TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
+
+ W_REG(&regs->xmtfifocmd, txfifo_cmd);
+ W_REG(&regs->xmtfifodef, txfifo_def);
+ W_REG(&regs->xmtfifodef1, txfifo_def1);
+
+ W_REG(&regs->xmtfifocmd, txfifo_cmd);
+
+ txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
+ }
+ /*
+ * need to propagate to shm location to be in sync since ucode/hw won't
+ * do this
+ */
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
+ wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
+ wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
+ ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
+ xmtfifo_sz[TX_AC_BK_FIFO]));
+ brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
+ ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
+ xmtfifo_sz[TX_BCMC_FIFO]));
+}
+
+/* This function is used for changing the tsf frac register
+ * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz
+ * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz
+ * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz
+ * HTPHY Formula is 2^26/freq(MHz) e.g.
+ * For spuron2 - 126MHz -> 2^26/126 = 532610.0
+ * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082
+ * For spuron: 123MHz -> 2^26/123 = 545600.5
+ * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341
+ * For spur off: 120MHz -> 2^26/120 = 559240.5
+ * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889
+ */
+
+void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID)) {
+ if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x2082);
+ W_REG(&regs->tsf_clk_frac_h, 0x8);
+ } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x5341);
+ W_REG(&regs->tsf_clk_frac_h, 0x8);
+ } else { /* 120Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x8889);
+ W_REG(&regs->tsf_clk_frac_h, 0x8);
+ }
+ } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
+ if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0x7CE0);
+ W_REG(&regs->tsf_clk_frac_h, 0xC);
+ } else { /* 80Mhz */
+ W_REG(&regs->tsf_clk_frac_l, 0xCCCD);
+ W_REG(&regs->tsf_clk_frac_h, 0xC);
+ }
+ }
+}
+
+/* Initialize GPIOs that are controlled by D11 core */
+static void brcms_c_gpio_init(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs;
+ u32 gc, gm;
+
+ regs = wlc_hw->regs;
+
+ /* use GPIO select 0 to get all gpio signals from the gpio out reg */
+ brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);
+
+ /*
+ * Common GPIO setup:
+ * G0 = LED 0 = WLAN Activity
+ * G1 = LED 1 = WLAN 2.4 GHz Radio State
+ * G2 = LED 2 = WLAN 5 GHz Radio State
+ * G4 = radio disable input (HI enabled, LO disabled)
+ */
+
+ gc = gm = 0;
+
+ /* Allocate GPIOs for mimo antenna diversity feature */
+ if (wlc_hw->antsel_type == ANTSEL_2x3) {
+ /* Enable antenna diversity, use 2x3 mode */
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
+ MHF3_ANTSEL_EN, BRCM_BAND_ALL);
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,
+ MHF3_ANTSEL_MODE, BRCM_BAND_ALL);
+
+ /* init superswitch control */
+ wlc_phy_antsel_init(wlc_hw->band->pi, false);
+
+ } else if (wlc_hw->antsel_type == ANTSEL_2x4) {
+ gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);
+ /*
+ * The board itself is powered by these GPIOs
+ * (when not sending pattern) so set them high
+ */
+ OR_REG(&regs->psm_gpio_oe,
+ (BOARD_GPIO_12 | BOARD_GPIO_13));
+ OR_REG(&regs->psm_gpio_out,
+ (BOARD_GPIO_12 | BOARD_GPIO_13));
+
+ /* Enable antenna diversity, use 2x4 mode */
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,
+ MHF3_ANTSEL_EN, BRCM_BAND_ALL);
+ brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,
+ BRCM_BAND_ALL);
+
+ /* Configure the desired clock to be 4Mhz */
+ brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV,
+ ANTSEL_CLKDIV_4MHZ);
+ }
+
+ /*
+ * gpio 9 controls the PA. ucode is responsible
+ * for wiggling out and oe
+ */
+ if (wlc_hw->boardflags & BFL_PACTRL)
+ gm |= gc |= BOARD_GPIO_PACTRL;
+
+ /* apply to gpiocontrol register */
+ ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
+}
+
+static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
+ const __le32 ucode[], const size_t nbytes)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ uint i;
+ uint count;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ count = (nbytes / sizeof(u32));
+
+ W_REG(&regs->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL));
+ (void)R_REG(&regs->objaddr);
+ for (i = 0; i < count; i++)
+ W_REG(&regs->objdata, le32_to_cpu(ucode[i]));
+
+}
+
+static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
+{
+ struct brcms_c_info *wlc;
+ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
+
+ wlc = wlc_hw->wlc;
+
+ if (wlc_hw->ucode_loaded)
+ return;
+
+ if (D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,
+ ucode->bcm43xx_16_mimosz);
+ wlc_hw->ucode_loaded = true;
+ } else
+ wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
+ "corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ } else if (D11REV_IS(wlc_hw->corerev, 24)) {
+ if (BRCMS_ISLCNPHY(wlc_hw->band)) {
+ brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn,
+ ucode->bcm43xx_24_lcnsz);
+ wlc_hw->ucode_loaded = true;
+ } else {
+ wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
+ "corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ }
+ }
+}
+
+void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)
+{
+ /* update sw state */
+ wlc_hw->bmac_phytxant = phytxant;
+
+ /* push to ucode if up */
+ if (!wlc_hw->up)
+ return;
+ brcms_c_ucode_txant_set(wlc_hw);
+
+}
+
+u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw)
+{
+ return (u16) wlc_hw->wlc->stf->txant;
+}
+
+void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
+{
+ wlc_hw->antsel_type = antsel_type;
+
+ /* Update the antsel type for phy module to use */
+ wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
+}
+
+static void brcms_c_fatal_error(struct brcms_c_info *wlc)
+{
+ wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+ wlc->pub->unit);
+ brcms_init(wlc->wl);
+}
+
+static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
+{
+ bool fatal = false;
+ uint unit;
+ uint intstatus, idx;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ struct wiphy *wiphy = wlc_hw->wlc->wiphy;
+
+ unit = wlc_hw->unit;
+
+ for (idx = 0; idx < NFIFO; idx++) {
+ /* read intstatus register and ignore any non-error bits */
+ intstatus =
+ R_REG(&regs->intctrlregs[idx].intstatus) & I_ERRORS;
+ if (!intstatus)
+ continue;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n",
+ unit, idx, intstatus);
+
+ if (intstatus & I_RO) {
+ wiphy_err(wiphy, "wl%d: fifo %d: receive fifo "
+ "overflow\n", unit, idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_PC) {
+ wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n",
+ unit, idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_PD) {
+ wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit,
+ idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_DE) {
+ wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol "
+ "error\n", unit, idx);
+ fatal = true;
+ }
+
+ if (intstatus & I_RU)
+ wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor "
+ "underflow\n", idx, unit);
+
+ if (intstatus & I_XU) {
+ wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo "
+ "underflow\n", idx, unit);
+ fatal = true;
+ }
+
+ if (fatal) {
+ brcms_c_fatal_error(wlc_hw->wlc); /* big hammer */
+ break;
+ } else
+ W_REG(&regs->intctrlregs[idx].intstatus,
+ intstatus);
+ }
+}
+
+void brcms_c_intrson(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ wlc->macintmask = wlc->defmacintmask;
+ W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
+}
+
+/*
+ * callback for siutils.c, which has only wlc handler, no wl they both check
+ * up, not only because there is no need to off/restore d11 interrupt but also
+ * because per-port code may require sync with valid interrupt.
+ */
+static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc)
+{
+ if (!wlc->hw->up)
+ return 0;
+
+ return brcms_intrsoff(wlc->wl);
+}
+
+static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask)
+{
+ if (!wlc->hw->up)
+ return;
+
+ brcms_intrsrestore(wlc->wl, macintmask);
+}
+
+u32 brcms_c_intrsoff(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ u32 macintmask;
+
+ if (!wlc_hw->clk)
+ return 0;
+
+ macintmask = wlc->macintmask; /* isr can still happen */
+
+ W_REG(&wlc_hw->regs->macintmask, 0);
+ (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */
+ udelay(1); /* ensure int line is no longer driven */
+ wlc->macintmask = 0;
+
+ /* return previous macintmask; resolve race between us and our isr */
+ return wlc->macintstatus ? 0 : macintmask;
+}
+
+void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ if (!wlc_hw->clk)
+ return;
+
+ wlc->macintmask = macintmask;
+ W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
+}
+
+static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
+ uint tx_fifo)
+{
+ u8 fifo = 1 << tx_fifo;
+
+ /* Two clients of this code, 11h Quiet period and scanning. */
+
+ /* only suspend if not already suspended */
+ if ((wlc_hw->suspended_fifos & fifo) == fifo)
+ return;
+
+ /* force the core awake only if not already */
+ if (wlc_hw->suspended_fifos == 0)
+ brcms_c_ucode_wake_override_set(wlc_hw,
+ BRCMS_WAKE_OVERRIDE_TXFIFO);
+
+ wlc_hw->suspended_fifos |= fifo;
+
+ if (wlc_hw->di[tx_fifo]) {
+ /*
+ * Suspending AMPDU transmissions in the middle can cause
+ * underflow which may result in mismatch between ucode and
+ * driver so suspend the mac before suspending the FIFO
+ */
+ if (BRCMS_PHY_11N_CAP(wlc_hw->band))
+ brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
+
+ dma_txsuspend(wlc_hw->di[tx_fifo]);
+
+ if (BRCMS_PHY_11N_CAP(wlc_hw->band))
+ brcms_c_enable_mac(wlc_hw->wlc);
+ }
+}
+
+static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
+ uint tx_fifo)
+{
+ /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case
+ * but need to be done here for PIO otherwise the watchdog will catch
+ * the inconsistency and fire
+ */
+ /* Two clients of this code, 11h Quiet period and scanning. */
+ if (wlc_hw->di[tx_fifo])
+ dma_txresume(wlc_hw->di[tx_fifo]);
+
+ /* allow core to sleep again */
+ if (wlc_hw->suspended_fifos == 0)
+ return;
+ else {
+ wlc_hw->suspended_fifos &= ~(1 << tx_fifo);
+ if (wlc_hw->suspended_fifos == 0)
+ brcms_c_ucode_wake_override_clear(wlc_hw,
+ BRCMS_WAKE_OVERRIDE_TXFIFO);
+ }
+}
+
+static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
+{
+ static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
+
+ if (on) {
+ /* suspend tx fifos */
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);
+ brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);
+
+ /* zero the address match register so we do not send ACKs */
+ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
+ null_ether_addr);
+ } else {
+ /* resume tx fifos */
+ brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);
+ brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);
+ brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);
+ brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);
+
+ /* Restore address */
+ brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET,
+ wlc_hw->etheraddr);
+ }
+
+ wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
+
+ if (on)
+ brcms_c_ucode_mute_override_set(wlc_hw);
+ else
+ brcms_c_ucode_mute_override_clear(wlc_hw);
+}
+
+/*
+ * Read and clear macintmask and macintstatus and intstatus registers.
+ * This routine should be called with interrupts off
+ * Return:
+ * -1 if brcms_deviceremoved(wlc) evaluates to true;
+ * 0 if the interrupt is not for us, or we are in some special cases;
+ * device interrupt status bits otherwise.
+ */
+static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u32 macintstatus;
+
+ /* macintstatus includes a DMA interrupt summary bit */
+ macintstatus = R_REG(&regs->macintstatus);
+
+ BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit,
+ macintstatus);
+
+ /* detect cardbus removed, in power down(suspend) and in reset */
+ if (brcms_deviceremoved(wlc))
+ return -1;
+
+ /* brcms_deviceremoved() succeeds even when the core is still resetting,
+ * handle that case here.
+ */
+ if (macintstatus == 0xffffffff)
+ return 0;
+
+ /* defer unsolicited interrupts */
+ macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask);
+
+ /* if not for us */
+ if (macintstatus == 0)
+ return 0;
+
+ /* interrupts are already turned off for CFE build
+ * Caution: For CFE Turning off the interrupts again has some undesired
+ * consequences
+ */
+ /* turn off the interrupts */
+ W_REG(&regs->macintmask, 0);
+ (void)R_REG(&regs->macintmask); /* sync readback */
+ wlc->macintmask = 0;
+
+ /* clear device interrupts */
+ W_REG(&regs->macintstatus, macintstatus);
+
+ /* MI_DMAINT is indication of non-zero intstatus */
+ if (macintstatus & MI_DMAINT)
+ /*
+ * only fifo interrupt enabled is I_RI in
+ * RX_FIFO. If MI_DMAINT is set, assume it
+ * is set and clear the interrupt.
+ */
+ W_REG(&regs->intctrlregs[RX_FIFO].intstatus,
+ DEF_RXINTMASK);
+
+ return macintstatus;
+}
+
+/* Update wlc->macintstatus and wlc->intstatus[]. */
+/* Return true if they are updated successfully. false otherwise */
+bool brcms_c_intrsupd(struct brcms_c_info *wlc)
+{
+ u32 macintstatus;
+
+ /* read and clear macintstatus and intstatus registers */
+ macintstatus = wlc_intstatus(wlc, false);
+
+ /* device is removed */
+ if (macintstatus == 0xffffffff)
+ return false;
+
+ /* update interrupt status in software */
+ wlc->macintstatus |= macintstatus;
+
+ return true;
+}
+
+/*
+ * First-level interrupt processing.
+ * Return true if this was our interrupt, false otherwise.
+ * *wantdpc will be set to true if further brcms_c_dpc() processing is required,
+ * false otherwise.
+ */
+bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ u32 macintstatus;
+
+ *wantdpc = false;
+
+ if (!wlc_hw->up || !wlc->macintmask)
+ return false;
+
+ /* read and clear macintstatus and intstatus registers */
+ macintstatus = wlc_intstatus(wlc, true);
+
+ if (macintstatus == 0xffffffff)
+ wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code"
+ " path\n");
+
+ /* it is not for us */
+ if (macintstatus == 0)
+ return false;
+
+ *wantdpc = true;
+
+ /* save interrupt status bits */
+ wlc->macintstatus = macintstatus;
+
+ return true;
+
+}
+
+void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u32 mc, mi;
+ struct wiphy *wiphy = wlc->wiphy;
+
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ wlc_hw->band->bandunit);
+
+ /*
+ * Track overlapping suspend requests
+ */
+ wlc_hw->mac_suspend_depth++;
+ if (wlc_hw->mac_suspend_depth > 1)
+ return;
+
+ /* force the core awake */
+ brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
+
+ mc = R_REG(&regs->maccontrol);
+
+ if (mc == 0xffffffff) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+ WARN_ON(!(mc & MCTL_EN_MAC));
+
+ mi = R_REG(&regs->macintstatus);
+ if (mi == 0xffffffff) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+ WARN_ON(mi & MI_MACSSPNDD);
+
+ brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0);
+
+ SPINWAIT(!(R_REG(&regs->macintstatus) & MI_MACSSPNDD),
+ BRCMS_MAX_MAC_SUSPEND);
+
+ if (!(R_REG(&regs->macintstatus) & MI_MACSSPNDD)) {
+ wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
+ " and MI_MACSSPNDD is still not on.\n",
+ wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);
+ wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
+ "psm_brc 0x%04x\n", wlc_hw->unit,
+ R_REG(&regs->psmdebug),
+ R_REG(&regs->phydebug),
+ R_REG(&regs->psm_brc));
+ }
+
+ mc = R_REG(&regs->maccontrol);
+ if (mc == 0xffffffff) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
+ }
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+ WARN_ON(mc & MCTL_EN_MAC);
+}
+
+void brcms_c_enable_mac(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u32 mc, mi;
+
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
+ wlc->band->bandunit);
+
+ /*
+ * Track overlapping suspend requests
+ */
+ wlc_hw->mac_suspend_depth--;
+ if (wlc_hw->mac_suspend_depth > 0)
+ return;
+
+ mc = R_REG(&regs->maccontrol);
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(mc & MCTL_EN_MAC);
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+
+ brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);
+ W_REG(&regs->macintstatus, MI_MACSSPNDD);
+
+ mc = R_REG(&regs->maccontrol);
+ WARN_ON(mc & MCTL_PSM_JMP_0);
+ WARN_ON(!(mc & MCTL_EN_MAC));
+ WARN_ON(!(mc & MCTL_PSM_RUN));
+
+ mi = R_REG(&regs->macintstatus);
+ WARN_ON(mi & MI_MACSSPNDD);
+
+ brcms_c_ucode_wake_override_clear(wlc_hw,
+ BRCMS_WAKE_OVERRIDE_MACSUSPEND);
+}
+
+void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
+{
+ wlc_hw->hw_stf_ss_opmode = stf_mode;
+
+ if (wlc_hw->clk)
+ brcms_upd_ofdm_pctl1_table(wlc_hw);
+}
+
+static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
+{
+ struct d11regs __iomem *regs;
+ u32 w, val;
+ struct wiphy *wiphy = wlc_hw->wlc->wiphy;
+
+ BCMMSG(wiphy, "wl%d\n", wlc_hw->unit);
+
+ regs = wlc_hw->regs;
+
+ /* Validate dchip register access */
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ w = R_REG(&regs->objdata);
+
+ /* Can we write and read back a 32bit register? */
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, (u32) 0xaa5555aa);
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ val = R_REG(&regs->objdata);
+ if (val != (u32) 0xaa5555aa) {
+ wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
+ "expected 0xaa5555aa\n", wlc_hw->unit, val);
+ return false;
+ }
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, (u32) 0x55aaaa55);
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ val = R_REG(&regs->objdata);
+ if (val != (u32) 0x55aaaa55) {
+ wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "
+ "expected 0x55aaaa55\n", wlc_hw->unit, val);
+ return false;
+ }
+
+ W_REG(&regs->objaddr, OBJADDR_SHM_SEL | 0);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, w);
+
+ /* clear CFPStart */
+ W_REG(&regs->tsf_cfpstart, 0);
+
+ w = R_REG(&regs->maccontrol);
+ if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&
+ (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {
+ wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = "
+ "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w,
+ (MCTL_IHR_EN | MCTL_WAKE),
+ (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));
+ return false;
+ }
+
+ return true;
+}
+
+#define PHYPLL_WAIT_US 100000
+
+void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
+{
+ struct d11regs __iomem *regs;
+ u32 tmp;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ tmp = 0;
+ regs = wlc_hw->regs;
+
+ if (on) {
+ if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
+ OR_REG(&regs->clk_ctl_st,
+ (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL |
+ CCS_ERSRC_REQ_PHYPLL));
+ SPINWAIT((R_REG(&regs->clk_ctl_st) &
+ (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT),
+ PHYPLL_WAIT_US);
+
+ tmp = R_REG(&regs->clk_ctl_st);
+ if ((tmp & (CCS_ERSRC_AVAIL_HT)) !=
+ (CCS_ERSRC_AVAIL_HT))
+ wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY"
+ " PLL failed\n", __func__);
+ } else {
+ OR_REG(&regs->clk_ctl_st,
+ (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL));
+ SPINWAIT((R_REG(&regs->clk_ctl_st) &
+ (CCS_ERSRC_AVAIL_D11PLL |
+ CCS_ERSRC_AVAIL_PHYPLL)) !=
+ (CCS_ERSRC_AVAIL_D11PLL |
+ CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);
+
+ tmp = R_REG(&regs->clk_ctl_st);
+ if ((tmp &
+ (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
+ !=
+ (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
+ wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on "
+ "PHY PLL failed\n", __func__);
+ }
+ } else {
+ /*
+ * Since the PLL may be shared, other cores can still
+ * be requesting it; so we'll deassert the request but
+ * not wait for status to comply.
+ */
+ AND_REG(&regs->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL);
+ tmp = R_REG(&regs->clk_ctl_st);
+ }
+}
+
+static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
+{
+ bool dev_gone;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);
+
+ if (dev_gone)
+ return;
+
+ if (wlc_hw->noreset)
+ return;
+
+ /* radio off */
+ wlc_phy_switch_radio(wlc_hw->band->pi, OFF);
+
+ /* turn off analog core */
+ wlc_phy_anacore(wlc_hw->band->pi, OFF);
+
+ /* turn off PHYPLL to save power */
+ brcms_b_core_phypll_ctl(wlc_hw, false);
+
+ wlc_hw->clk = false;
+ ai_core_disable(wlc_hw->sih, 0);
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+}
+
+static void brcms_c_flushqueues(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ uint i;
+
+ /* free any posted tx packets */
+ for (i = 0; i < NFIFO; i++)
+ if (wlc_hw->di[i]) {
+ dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
+ wlc->core->txpktpend[i] = 0;
+ BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i);
+ }
+
+ /* free any posted rx packets */
+ dma_rxreclaim(wlc_hw->di[RX_FIFO]);
+}
+
+static u16
+brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u16 __iomem *objdata_lo = (u16 __iomem *)&regs->objdata;
+ u16 __iomem *objdata_hi = objdata_lo + 1;
+ u16 v;
+
+ W_REG(&regs->objaddr, sel | (offset >> 2));
+ (void)R_REG(&regs->objaddr);
+ if (offset & 2)
+ v = R_REG(objdata_hi);
+ else
+ v = R_REG(objdata_lo);
+
+ return v;
+}
+
+static void
+brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,
+ u32 sel)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ u16 __iomem *objdata_lo = (u16 __iomem *)&regs->objdata;
+ u16 __iomem *objdata_hi = objdata_lo + 1;
+
+ W_REG(&regs->objaddr, sel | (offset >> 2));
+ (void)R_REG(&regs->objaddr);
+ if (offset & 2)
+ W_REG(objdata_hi, v);
+ else
+ W_REG(objdata_lo, v);
+}
+
+/*
+ * Read a single u16 from shared memory.
+ * SHM 'offset' needs to be an even address
+ */
+u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)
+{
+ return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);
+}
+
+/*
+ * Write a single u16 to shared memory.
+ * SHM 'offset' needs to be an even address
+ */
+void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)
+{
+ brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);
+}
+
+/*
+ * Copy a buffer to shared memory of specified type .
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ * 'sel' selects the type of memory
+ */
+void
+brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset,
+ const void *buf, int len, u32 sel)
+{
+ u16 v;
+ const u8 *p = (const u8 *)buf;
+ int i;
+
+ if (len <= 0 || (offset & 1) || (len & 1))
+ return;
+
+ for (i = 0; i < len; i += 2) {
+ v = p[i] | (p[i + 1] << 8);
+ brcms_b_write_objmem(wlc_hw, offset + i, v, sel);
+ }
+}
+
+/*
+ * Copy a piece of shared memory of specified type to a buffer .
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ * 'sel' selects the type of memory
+ */
+void
+brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,
+ int len, u32 sel)
+{
+ u16 v;
+ u8 *p = (u8 *) buf;
+ int i;
+
+ if (len <= 0 || (offset & 1) || (len & 1))
+ return;
+
+ for (i = 0; i < len; i += 2) {
+ v = brcms_b_read_objmem(wlc_hw, offset + i, sel);
+ p[i] = v & 0xFF;
+ p[i + 1] = (v >> 8) & 0xFF;
+ }
+}
+
+/* Copy a buffer to shared memory.
+ * SHM 'offset' needs to be an even address and
+ * Buffer length 'len' must be an even number of bytes
+ */
+static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
+ const void *buf, int len)
+{
+ brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
+}
+
+static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw,
+ u16 SRL, u16 LRL)
+{
+ wlc_hw->SRL = SRL;
+ wlc_hw->LRL = LRL;
+
+ /* write retry limit to SCR, shouldn't need to suspend */
+ if (wlc_hw->up) {
+ W_REG(&wlc_hw->regs->objaddr,
+ OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL);
+ W_REG(&wlc_hw->regs->objaddr,
+ OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
+ (void)R_REG(&wlc_hw->regs->objaddr);
+ W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL);
+ }
+}
+
+static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit)
+{
+ if (set) {
+ if (mboolisset(wlc_hw->pllreq, req_bit))
+ return;
+
+ mboolset(wlc_hw->pllreq, req_bit);
+
+ if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
+ if (!wlc_hw->sbclk)
+ brcms_b_xtal(wlc_hw, ON);
+ }
+ } else {
+ if (!mboolisset(wlc_hw->pllreq, req_bit))
+ return;
+
+ mboolclr(wlc_hw->pllreq, req_bit);
+
+ if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {
+ if (wlc_hw->sbclk)
+ brcms_b_xtal(wlc_hw, OFF);
+ }
+ }
+}
+
+static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
+{
+ wlc_hw->antsel_avail = antsel_avail;
+}
+
+/*
+ * conditions under which the PM bit should be set in outgoing frames
+ * and STAY_AWAKE is meaningful
+ */
+static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
+{
+ struct brcms_bss_cfg *cfg = wlc->bsscfg;
+
+ /* disallow PS when one of the following global conditions meets */
+ if (!wlc->pub->associated)
+ return false;
+
+ /* disallow PS when one of these meets when not scanning */
+ if (wlc->monitor)
+ return false;
+
+ if (cfg->associated) {
+ /*
+ * disallow PS when one of the following
+ * bsscfg specific conditions meets
+ */
+ if (!cfg->BSS)
+ return false;
+
+ return false;
+ }
+
+ return true;
+}
+
+static void brcms_c_statsupd(struct brcms_c_info *wlc)
+{
+ int i;
+ struct macstat macstats;
+#ifdef BCMDBG
+ u16 delta;
+ u16 rxf0ovfl;
+ u16 txfunfl[NFIFO];
+#endif /* BCMDBG */
+
+ /* if driver down, make no sense to update stats */
+ if (!wlc->pub->up)
+ return;
+
+#ifdef BCMDBG
+ /* save last rx fifo 0 overflow count */
+ rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
+
+ /* save last tx fifo underflow count */
+ for (i = 0; i < NFIFO; i++)
+ txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
+#endif /* BCMDBG */
+
+ /* Read mac stats from contiguous shared memory */
+ brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats,
+ sizeof(struct macstat), OBJADDR_SHM_SEL);
+
+#ifdef BCMDBG
+ /* check for rx fifo 0 overflow */
+ delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
+ if (delta)
+ wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
+ wlc->pub->unit, delta);
+
+ /* check for tx fifo underflows */
+ for (i = 0; i < NFIFO; i++) {
+ delta =
+ (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
+ txfunfl[i]);
+ if (delta)
+ wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
+ "\n", wlc->pub->unit, delta, i);
+ }
+#endif /* BCMDBG */
+
+ /* merge counters from dma module */
+ for (i = 0; i < NFIFO; i++) {
+ if (wlc->hw->di[i])
+ dma_counterreset(wlc->hw->di[i]);
+ }
+}
+
+static void brcms_b_reset(struct brcms_hardware *wlc_hw)
+{
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /* reset the core */
+ if (!brcms_deviceremoved(wlc_hw->wlc))
+ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
+
+ /* purge the dma rings */
+ brcms_c_flushqueues(wlc_hw->wlc);
+}
+
void brcms_c_reset(struct brcms_c_info *wlc)
{
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
@@ -414,207 +3227,675 @@ void brcms_c_reset(struct brcms_c_info *wlc)
brcms_b_reset(wlc->hw);
}
-void brcms_c_fatal_error(struct brcms_c_info *wlc)
-{
- wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
- wlc->pub->unit);
- brcms_init(wlc->wl);
-}
-
/* Return the channel the driver should initialize during brcms_c_init.
* the channel may have to be changed from the currently configured channel
* if other configurations are in conflict (bandlocked, 11n mode disabled,
* invalid channel for current country, etc.)
*/
-static chanspec_t brcms_c_init_chanspec(struct brcms_c_info *wlc)
+static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc)
{
- chanspec_t chanspec =
+ u16 chanspec =
1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE |
WL_CHANSPEC_BAND_2G;
return chanspec;
}
-struct scb global_scb;
-
-static void brcms_c_init_scb(struct brcms_c_info *wlc, struct scb *scb)
+void brcms_c_init_scb(struct scb *scb)
{
int i;
+
+ memset(scb, 0, sizeof(struct scb));
scb->flags = SCB_WMECAP | SCB_HTCAP;
- for (i = 0; i < NUMPRIO; i++)
+ for (i = 0; i < NUMPRIO; i++) {
scb->seqnum[i] = 0;
+ scb->seqctl[i] = 0xFFFF;
+ }
+
+ scb->seqctl_nonqos = 0xFFFF;
+ scb->magic = SCB_MAGIC;
}
-void brcms_c_init(struct brcms_c_info *wlc)
-{
- d11regs_t *regs;
- chanspec_t chanspec;
- int i;
- struct brcms_bss_cfg *bsscfg;
- bool mute = false;
+/* d11 core init
+ * reset PSM
+ * download ucode/PCM
+ * let ucode run to suspended
+ * download ucode inits
+ * config other core registers
+ * init dma
+ */
+static void brcms_b_coreinit(struct brcms_c_info *wlc)
+{
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs;
+ u32 sflags;
+ uint bcnint_us;
+ uint i = 0;
+ bool fifosz_fixup = false;
+ int err = 0;
+ u16 buf[NFIFO];
+ struct wiphy *wiphy = wlc->wiphy;
+ struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
- BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+ regs = wlc_hw->regs;
- regs = wlc->regs;
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ /* reset PSM */
+ brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
- /* This will happen if a big-hammer was executed. In that case, we want to go back
- * to the channel that we were on and not new channel
+ brcms_ucode_download(wlc_hw);
+ /*
+ * FIFOSZ fixup. driver wants to controls the fifo allocation.
*/
- if (wlc->pub->associated)
- chanspec = wlc->home_chanspec;
- else
- chanspec = brcms_c_init_chanspec(wlc);
+ fifosz_fixup = true;
- brcms_b_init(wlc->hw, chanspec, mute);
+ /* let the PSM run to the suspended state, set mode to BSS STA */
+ W_REG(&regs->macintstatus, -1);
+ brcms_b_mctrl(wlc_hw, ~0,
+ (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
- /* update beacon listen interval */
- brcms_c_bcn_li_upd(wlc);
+ /* wait for ucode to self-suspend after auto-init */
+ SPINWAIT(((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0),
+ 1000 * 1000);
+ if ((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0)
+ wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
+ "suspend!\n", wlc_hw->unit);
- /* the world is new again, so is our reported rate */
- brcms_c_reprate_init(wlc);
+ brcms_c_gpio_init(wlc);
- /* write ethernet address to core */
- FOREACH_BSS(wlc, i, bsscfg) {
- brcms_c_set_mac(bsscfg);
- brcms_c_set_bssid(bsscfg);
+ sflags = ai_core_sflags(wlc_hw->sih, 0, 0);
+
+ if (D11REV_IS(wlc_hw->corerev, 23)) {
+ if (BRCMS_ISNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+ " %d\n", __func__, wlc_hw->unit,
+ wlc_hw->corerev);
+ } else if (D11REV_IS(wlc_hw->corerev, 24)) {
+ if (BRCMS_ISLCNPHY(wlc_hw->band))
+ brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24);
+ else
+ wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+ " %d\n", __func__, wlc_hw->unit,
+ wlc_hw->corerev);
+ } else {
+ wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
+ __func__, wlc_hw->unit, wlc_hw->corerev);
+ }
+
+ /* For old ucode, txfifo sizes needs to be modified(increased) */
+ if (fifosz_fixup == true)
+ brcms_b_corerev_fifofixup(wlc_hw);
+
+ /* check txfifo allocations match between ucode and driver */
+ buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
+ if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
+ i = TX_AC_BE_FIFO;
+ err = -1;
+ }
+ buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
+ if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
+ i = TX_AC_VI_FIFO;
+ err = -1;
+ }
+ buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
+ buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
+ buf[TX_AC_BK_FIFO] &= 0xff;
+ if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
+ i = TX_AC_BK_FIFO;
+ err = -1;
+ }
+ if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
+ i = TX_AC_VO_FIFO;
+ err = -1;
+ }
+ buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
+ buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
+ buf[TX_BCMC_FIFO] &= 0xff;
+ if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
+ i = TX_BCMC_FIFO;
+ err = -1;
+ }
+ if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
+ i = TX_ATIM_FIFO;
+ err = -1;
}
+ if (err != 0)
+ wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
+ " driver size %d index %d\n", buf[i],
+ wlc_hw->xmtfifo_sz[i], i);
- /* Update tsf_cfprep if associated and up */
- if (wlc->pub->associated) {
- FOREACH_BSS(wlc, i, bsscfg) {
- if (bsscfg->up) {
- u32 bi;
+ /* make sure we can still talk to the mac */
+ WARN_ON(R_REG(&regs->maccontrol) == 0xffffffff);
- /* get beacon period and convert to uS */
- bi = bsscfg->current_bss->beacon_period << 10;
- /*
- * update since init path would reset
- * to default value
- */
- W_REG(&regs->tsf_cfprep,
- (bi << CFPREP_CBI_SHIFT));
+ /* band-specific inits done by wlc_bsinit() */
- /* Update maccontrol PM related bits */
- brcms_c_set_ps_ctrl(wlc);
+ /* Set up frame burst size and antenna swap threshold init values */
+ brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
+ brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
- break;
- }
- }
- }
+ /* enable one rx interrupt per received frame */
+ W_REG(&regs->intrcvlazy[0], (1 << IRL_FC_SHIFT));
- brcms_c_bandinit_ordered(wlc, chanspec);
+ /* set the station mode (BSS STA) */
+ brcms_b_mctrl(wlc_hw,
+ (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
+ (MCTL_INFRA | MCTL_DISCARD_PMQ));
- brcms_c_init_scb(wlc, &global_scb);
+ /* set up Beacon interval */
+ bcnint_us = 0x8000 << 10;
+ W_REG(&regs->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT));
+ W_REG(&regs->tsf_cfpstart, bcnint_us);
+ W_REG(&regs->macintstatus, MI_GP1);
- /* init probe response timeout */
- brcms_c_write_shm(wlc, M_PRS_MAXTIME, wlc->prb_resp_timeout);
+ /* write interrupt mask */
+ W_REG(&regs->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK);
- /* init max burst txop (framebursting) */
- brcms_c_write_shm(wlc, M_MBURST_TXOP,
- (wlc->
- _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
+ /* allow the MAC to control the PHY clock (dynamic on/off) */
+ brcms_b_macphyclk_set(wlc_hw, ON);
- /* initialize maximum allowed duty cycle */
- brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
- brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
+ /* program dynamic clock control fast powerup delay register */
+ wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
+ W_REG(&regs->scc_fastpwrup_dly, wlc->fastpwrup_dly);
- /* Update some shared memory locations related to max AMPDU size allowed to received */
- brcms_c_ampdu_shm_upd(wlc->ampdu);
+ /* tell the ucode the corerev */
+ brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
- /* band-specific inits */
- brcms_c_bsinit(wlc);
+ /* tell the ucode MAC capabilities */
+ brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
+ (u16) (wlc_hw->machwcap & 0xffff));
+ brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
+ (u16) ((wlc_hw->
+ machwcap >> 16) & 0xffff));
- /* Enable EDCF mode (while the MAC is suspended) */
- if (EDCF_ENAB(wlc->pub)) {
- OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
- brcms_c_edcf_setparams(wlc, false);
- }
+ /* write retry limits to SCR, this done after PSM init */
+ W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, wlc_hw->SRL);
+ W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
+ (void)R_REG(&regs->objaddr);
+ W_REG(&regs->objdata, wlc_hw->LRL);
- /* Init precedence maps for empty FIFOs */
- brcms_c_tx_prec_map_init(wlc);
+ /* write rate fallback retry limits */
+ brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
+ brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
- /* read the ucode version if we have not yet done so */
- if (wlc->ucode_rev == 0) {
- wlc->ucode_rev =
- brcms_c_read_shm(wlc, M_BOM_REV_MAJOR) << NBITS(u16);
- wlc->ucode_rev |= brcms_c_read_shm(wlc, M_BOM_REV_MINOR);
+ AND_REG(&regs->ifs_ctl, 0x0FFF);
+ W_REG(&regs->ifs_aifsn, EDCF_AIFSN_MIN);
+
+ /* init the tx dma engines */
+ for (i = 0; i < NFIFO; i++) {
+ if (wlc_hw->di[i])
+ dma_txinit(wlc_hw->di[i]);
}
- /* ..now really unleash hell (allow the MAC out of suspend) */
- brcms_c_enable_mac(wlc);
+ /* init the rx dma engine(s) and post receive buffers */
+ dma_rxinit(wlc_hw->di[RX_FIFO]);
+ dma_rxfill(wlc_hw->di[RX_FIFO]);
+}
- /* clear tx flow control */
- brcms_c_txflowcontrol_reset(wlc);
+void
+static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
+ bool mute) {
+ u32 macintmask;
+ bool fastclk;
+ struct brcms_c_info *wlc = wlc_hw->wlc;
- /* clear tx data fifo suspends */
- wlc->tx_suspended = false;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
- /* enable the RF Disable Delay timer */
- W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
+ /* request FAST clock if not on */
+ fastclk = wlc_hw->forcefastclk;
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
- /* initialize mpc delay */
- wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+ /* disable interrupts */
+ macintmask = brcms_intrsoff(wlc->wl);
+
+ /* set up the specified band and chanspec */
+ brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec));
+ wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
+
+ /* do one-time phy inits and calibration */
+ wlc_phy_cal_init(wlc_hw->band->pi);
+
+ /* core-specific initialization */
+ brcms_b_coreinit(wlc);
+
+ /* suspend the tx fifos and mute the phy for preism cac time */
+ if (mute)
+ brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
+
+ /* band-specific inits */
+ brcms_b_bsinit(wlc, chanspec);
+
+ /* restore macintmask */
+ brcms_intrsrestore(wlc->wl, macintmask);
+
+ /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
+ * is suspended and brcms_c_enable_mac() will clear this override bit.
+ */
+ mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
/*
- * Initialize WME parameters; if they haven't been set by some other
- * mechanism (IOVar, etc) then read them from the hardware.
+ * initialize mac_suspend_depth to 1 to match ucode
+ * initial suspended state
*/
- if (BRCMS_WME_RETRY_SHORT_GET(wlc, 0) == 0) {
- /* Uninitialized; read from HW */
- int ac;
+ wlc_hw->mac_suspend_depth = 1;
- for (ac = 0; ac < AC_COUNT; ac++) {
- wlc->wme_retries[ac] =
- brcms_c_read_shm(wlc, M_AC_TXLMT_ADDR(ac));
+ /* restore the clk */
+ if (!fastclk)
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+}
+
+static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
+ u16 chanspec)
+{
+ /* Save our copy of the chanspec */
+ wlc->chanspec = chanspec;
+
+ /* Set the chanspec and power limits for this locale */
+ brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX);
+
+ if (wlc->stf->ss_algosel_auto)
+ brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
+ chanspec);
+
+ brcms_c_stf_ss_update(wlc, wlc->band);
+}
+
+static void
+brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)
+{
+ brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
+ wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N),
+ brcms_chspec_bw(wlc->default_bss->chanspec),
+ wlc->stf->txstreams);
+}
+
+/* derive wlc->band->basic_rate[] table from 'rateset' */
+static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
+ struct brcms_c_rateset *rateset)
+{
+ u8 rate;
+ u8 mandatory;
+ u8 cck_basic = 0;
+ u8 ofdm_basic = 0;
+ u8 *br = wlc->band->basic_rate;
+ uint i;
+
+ /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
+ memset(br, 0, BRCM_MAXRATE + 1);
+
+ /* For each basic rate in the rates list, make an entry in the
+ * best basic lookup.
+ */
+ for (i = 0; i < rateset->count; i++) {
+ /* only make an entry for a basic rate */
+ if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
+ continue;
+
+ /* mask off basic bit */
+ rate = (rateset->rates[i] & BRCMS_RATE_MASK);
+
+ if (rate > BRCM_MAXRATE) {
+ wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
+ "invalid rate 0x%X in rate set\n",
+ rateset->rates[i]);
+ continue;
+ }
+
+ br[rate] = rate;
+ }
+
+ /* The rate lookup table now has non-zero entries for each
+ * basic rate, equal to the basic rate: br[basicN] = basicN
+ *
+ * To look up the best basic rate corresponding to any
+ * particular rate, code can use the basic_rate table
+ * like this
+ *
+ * basic_rate = wlc->band->basic_rate[tx_rate]
+ *
+ * Make sure there is a best basic rate entry for
+ * every rate by walking up the table from low rates
+ * to high, filling in holes in the lookup table
+ */
+
+ for (i = 0; i < wlc->band->hw_rateset.count; i++) {
+ rate = wlc->band->hw_rateset.rates[i];
+
+ if (br[rate] != 0) {
+ /* This rate is a basic rate.
+ * Keep track of the best basic rate so far by
+ * modulation type.
+ */
+ if (is_ofdm_rate(rate))
+ ofdm_basic = rate;
+ else
+ cck_basic = rate;
+
+ continue;
}
+
+ /* This rate is not a basic rate so figure out the
+ * best basic rate less than this rate and fill in
+ * the hole in the table
+ */
+
+ br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;
+
+ if (br[rate] != 0)
+ continue;
+
+ if (is_ofdm_rate(rate)) {
+ /*
+ * In 11g and 11a, the OFDM mandatory rates
+ * are 6, 12, and 24 Mbps
+ */
+ if (rate >= BRCM_RATE_24M)
+ mandatory = BRCM_RATE_24M;
+ else if (rate >= BRCM_RATE_12M)
+ mandatory = BRCM_RATE_12M;
+ else
+ mandatory = BRCM_RATE_6M;
+ } else {
+ /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */
+ mandatory = rate;
+ }
+
+ br[rate] = mandatory;
}
}
-void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
+ u16 chanspec)
{
- wlc->bcnmisc_monitor = promisc;
- brcms_c_mac_bcn_promisc(wlc);
+ struct brcms_c_rateset default_rateset;
+ uint parkband;
+ uint i, band_order[2];
+
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+ /*
+ * We might have been bandlocked during down and the chip
+ * power-cycled (hibernate). Figure out the right band to park on
+ */
+ if (wlc->bandlocked || wlc->pub->_nbands == 1) {
+ /* updated in brcms_c_bandlock() */
+ parkband = wlc->band->bandunit;
+ band_order[0] = band_order[1] = parkband;
+ } else {
+ /* park on the band of the specified chanspec */
+ parkband = chspec_bandunit(chanspec);
+
+ /* order so that parkband initialize last */
+ band_order[0] = parkband ^ 1;
+ band_order[1] = parkband;
+ }
+
+ /* make each band operational, software state init */
+ for (i = 0; i < wlc->pub->_nbands; i++) {
+ uint j = band_order[i];
+
+ wlc->band = wlc->bandstate[j];
+
+ brcms_default_rateset(wlc, &default_rateset);
+
+ /* fill in hw_rate */
+ brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
+ false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N));
+
+ /* init basic rate lookup */
+ brcms_c_rate_lookup_init(wlc, &default_rateset);
+ }
+
+ /* sync up phy/radio chanspec */
+ brcms_c_set_phy_chanspec(wlc, chanspec);
}
-void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
+static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
{
- if ((AP_ENAB(wlc->pub) && (N_ENAB(wlc->pub) || wlc->band->gmode)) ||
- wlc->bcnmisc_ibss || wlc->bcnmisc_scan || wlc->bcnmisc_monitor)
- brcms_c_mctrl(wlc, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
+ if (wlc->bcnmisc_monitor)
+ brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
else
- brcms_c_mctrl(wlc, MCTL_BCNS_PROMISC, 0);
+ brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
+}
+
+void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+{
+ wlc->bcnmisc_monitor = promisc;
+ brcms_c_mac_bcn_promisc(wlc);
}
/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
-void brcms_c_mac_promisc(struct brcms_c_info *wlc)
+static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
{
u32 promisc_bits = 0;
- /* promiscuous mode just sets MCTL_PROMISC
- * Note: APs get all BSS traffic without the need to set the MCTL_PROMISC bit
- * since all BSS data traffic is directed at the AP
+ /*
+ * promiscuous mode just sets MCTL_PROMISC
+ * Note: APs get all BSS traffic without the need to set
+ * the MCTL_PROMISC bit since all BSS data traffic is
+ * directed at the AP
*/
- if (PROMISC_ENAB(wlc->pub) && !AP_ENAB(wlc->pub))
+ if (wlc->pub->promisc)
promisc_bits |= MCTL_PROMISC;
/* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
* Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
* handled in brcms_c_mac_bcn_promisc()
*/
- if (MONITOR_ENAB(wlc))
+ if (wlc->monitor)
promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
- brcms_c_mctrl(wlc, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+ brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+}
+
+/*
+ * ucode, hwmac update
+ * Channel dependent updates for ucode and hw
+ */
+static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
+{
+ /* enable or disable any active IBSSs depending on whether or not
+ * we are on the home channel
+ */
+ if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) {
+ if (wlc->pub->associated) {
+ /*
+ * BMAC_NOTE: This is something that should be fixed
+ * in ucode inits. I think that the ucode inits set
+ * up the bcn templates and shm values with a bogus
+ * beacon. This should not be done in the inits. If
+ * ucode needs to set up a beacon for testing, the
+ * test routines should write it down, not expect the
+ * inits to populate a bogus beacon.
+ */
+ if (BRCMS_PHY_11N_CAP(wlc->band))
+ brcms_b_write_shm(wlc->hw,
+ M_BCN_TXTSF_OFFSET, 0);
+ }
+ } else {
+ /* disable an active IBSS if we are not on the home channel */
+ }
+
+ /* update the various promisc bits */
+ brcms_c_mac_bcn_promisc(wlc);
+ brcms_c_mac_promisc(wlc);
+}
+
+static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
+ u8 basic_rate)
+{
+ u8 phy_rate, index;
+ u8 basic_phy_rate, basic_index;
+ u16 dir_table, basic_table;
+ u16 basic_ptr;
+
+ /* Shared memory address for the table we are reading */
+ dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
+
+ /* Shared memory address for the table we are writing */
+ basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
+
+ /*
+ * for a given rate, the LS-nibble of the PLCP SIGNAL field is
+ * the index into the rate table.
+ */
+ phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
+ basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
+ index = phy_rate & 0xf;
+ basic_index = basic_phy_rate & 0xf;
+
+ /* Find the SHM pointer to the ACK rate entry by looking in the
+ * Direct-map Table
+ */
+ basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));
+
+ /* Update the SHM BSS-basic-rate-set mapping table with the pointer
+ * to the correct basic rate for the given incoming rate
+ */
+ brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);
+}
+
+static const struct brcms_c_rateset *
+brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
+{
+ const struct brcms_c_rateset *rs_dflt;
+
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ if (wlc->band->bandtype == BRCM_BAND_5G)
+ rs_dflt = &ofdm_mimo_rates;
+ else
+ rs_dflt = &cck_ofdm_mimo_rates;
+ } else if (wlc->band->gmode)
+ rs_dflt = &cck_ofdm_rates;
+ else
+ rs_dflt = &cck_rates;
+
+ return rs_dflt;
+}
+
+static void brcms_c_set_ratetable(struct brcms_c_info *wlc)
+{
+ const struct brcms_c_rateset *rs_dflt;
+ struct brcms_c_rateset rs;
+ u8 rate, basic_rate;
+ uint i;
+
+ rs_dflt = brcms_c_rateset_get_hwrs(wlc);
+
+ brcms_c_rateset_copy(rs_dflt, &rs);
+ brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
+
+ /* walk the phy rate table and update SHM basic rate lookup table */
+ for (i = 0; i < rs.count; i++) {
+ rate = rs.rates[i] & BRCMS_RATE_MASK;
+
+ /* for a given rate brcms_basic_rate returns the rate at
+ * which a response ACK/CTS should be sent.
+ */
+ basic_rate = brcms_basic_rate(wlc, rate);
+ if (basic_rate == 0)
+ /* This should only happen if we are using a
+ * restricted rateset.
+ */
+ basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
+
+ brcms_c_write_rate_shm(wlc, rate, basic_rate);
+ }
+}
+
+/* band-specific init */
+static void brcms_c_bsinit(struct brcms_c_info *wlc)
+{
+ BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
+ wlc->pub->unit, wlc->band->bandunit);
+
+ /* write ucode ACK/CTS rate table */
+ brcms_c_set_ratetable(wlc);
+
+ /* update some band specific mac configuration */
+ brcms_c_ucode_mac_upd(wlc);
+
+ /* init antenna selection */
+ brcms_c_antsel_init(wlc->asi);
+
+}
+
+/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
+static int
+brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
+ bool writeToShm)
+{
+ int idle_busy_ratio_x_16 = 0;
+ uint offset =
+ isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
+ M_TX_IDLE_BUSY_RATIO_X_16_CCK;
+ if (duty_cycle > 100 || duty_cycle < 0) {
+ wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n",
+ wlc->pub->unit);
+ return -EINVAL;
+ }
+ if (duty_cycle)
+ idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
+ /* Only write to shared memory when wl is up */
+ if (writeToShm)
+ brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16);
+
+ if (isOFDM)
+ wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
+ else
+ wlc->tx_duty_cycle_cck = (u16) duty_cycle;
+
+ return 0;
+}
+
+/*
+ * Initialize the base precedence map for dequeueing
+ * from txq based on WME settings
+ */
+static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
+{
+ wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
+ memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
+
+ wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
+ wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
+ wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
+ wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
+}
+
+static void
+brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
+ struct brcms_txq_info *qi, bool on, int prio)
+{
+ /* transmit flowcontrol is not yet implemented */
+}
+
+static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
+{
+ struct brcms_txq_info *qi;
+
+ for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
+ if (qi->stopped) {
+ brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
+ qi->stopped = 0;
+ }
+ }
}
/* push sw hps and wake state through hardware */
-void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
+static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
{
u32 v1, v2;
bool hps;
bool awake_before;
- hps = PS_ALLOWED(wlc);
+ hps = brcms_c_ps_allowed(wlc);
BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps);
@@ -623,28 +3904,25 @@ void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
if (hps)
v2 |= MCTL_HPS;
- brcms_c_mctrl(wlc, MCTL_WAKE | MCTL_HPS, v2);
+ brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);
awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));
if (!awake_before)
brcms_b_wait_for_wake(wlc->hw);
-
}
/*
* Write this BSS config's MAC address to core.
* Updates RXE match engine.
*/
-int brcms_c_set_mac(struct brcms_bss_cfg *cfg)
+static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)
{
int err = 0;
- struct brcms_c_info *wlc = cfg->wlc;
+ struct brcms_c_info *wlc = bsscfg->wlc;
- if (cfg == wlc->cfg) {
- /* enter the MAC addr into the RXE match registers */
- brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, cfg->cur_etheraddr);
- }
+ /* enter the MAC addr into the RXE match registers */
+ brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr);
brcms_c_ampdu_macaddr_upd(wlc);
@@ -654,30 +3932,29 @@ int brcms_c_set_mac(struct brcms_bss_cfg *cfg)
/* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).
* Updates RXE match engine.
*/
-void brcms_c_set_bssid(struct brcms_bss_cfg *cfg)
+static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)
{
- struct brcms_c_info *wlc = cfg->wlc;
+ /* we need to update BSSID in RXE match registers */
+ brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);
+}
- /* if primary config, we need to update BSSID in RXE match registers */
- if (cfg == wlc->cfg) {
- brcms_c_set_addrmatch(wlc, RCM_BSSID_OFFSET, cfg->BSSID);
- }
-#ifdef SUPPORT_HWKEYS
- else if (BSSCFG_STA(cfg) && cfg->BSS) {
- brcms_c_rcmta_add_bssid(wlc, cfg);
+static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
+{
+ wlc_hw->shortslot = shortslot;
+
+ if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) {
+ brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
+ brcms_b_update_slot_timing(wlc_hw, shortslot);
+ brcms_c_enable_mac(wlc_hw->wlc);
}
-#endif
}
/*
* Suspend the the MAC and update the slot timing
* for standard 11b/g (20us slots) or shortslot 11g (9us slots).
*/
-void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
+static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
{
- int idx;
- struct brcms_bss_cfg *cfg;
-
/* use the override if it is set */
if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO)
shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON);
@@ -687,91 +3964,84 @@ void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)
wlc->shortslot = shortslot;
- /* update the capability based on current shortslot mode */
- FOREACH_BSS(wlc, idx, cfg) {
- if (!cfg->associated)
- continue;
- cfg->current_bss->capability &=
- ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
- if (wlc->shortslot)
- cfg->current_bss->capability |=
- WLAN_CAPABILITY_SHORT_SLOT_TIME;
- }
-
brcms_b_set_shortslot(wlc->hw, shortslot);
}
-static u8 brcms_c_local_constraint_qdbm(struct brcms_c_info *wlc)
+static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
{
- u8 local;
- s16 local_max;
-
- local = BRCMS_TXPWR_MAX;
- if (wlc->pub->associated &&
- (brcmu_chspec_ctlchan(wlc->chanspec) ==
- brcmu_chspec_ctlchan(wlc->home_chanspec))) {
+ if (wlc->home_chanspec != chanspec) {
+ wlc->home_chanspec = chanspec;
- /* get the local power constraint if we are on the AP's
- * channel [802.11h, 7.3.2.13]
- */
- /* Clamp the value between 0 and BRCMS_TXPWR_MAX w/o
- * overflowing the target */
- local_max =
- (wlc->txpwr_local_max -
- wlc->txpwr_local_constraint) * BRCMS_TXPWR_DB_FACTOR;
- if (local_max > 0 && local_max < BRCMS_TXPWR_MAX)
- return (u8) local_max;
- if (local_max < 0)
- return 0;
+ if (wlc->bsscfg->associated)
+ wlc->bsscfg->current_bss->chanspec = chanspec;
}
-
- return local;
}
-/* propagate home chanspec to all bsscfgs in case bsscfg->current_bss->chanspec is referenced */
-void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, chanspec_t chanspec)
+void
+brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
+ bool mute, struct txpwr_limits *txpwr)
{
- if (wlc->home_chanspec != chanspec) {
- int idx;
- struct brcms_bss_cfg *cfg;
+ uint bandunit;
- wlc->home_chanspec = chanspec;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
- FOREACH_BSS(wlc, idx, cfg) {
- if (!cfg->associated)
- continue;
+ wlc_hw->chanspec = chanspec;
- cfg->current_bss->chanspec = chanspec;
+ /* Switch bands if necessary */
+ if (wlc_hw->_nbands > 1) {
+ bandunit = chspec_bandunit(chanspec);
+ if (wlc_hw->band->bandunit != bandunit) {
+ /* brcms_b_setband disables other bandunit,
+ * use light band switch if not up yet
+ */
+ if (wlc_hw->up) {
+ wlc_phy_chanspec_radio_set(wlc_hw->
+ bandstate[bandunit]->
+ pi, chanspec);
+ brcms_b_setband(wlc_hw, bandunit, chanspec);
+ } else {
+ brcms_c_setxband(wlc_hw, bandunit);
+ }
}
+ }
+ wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
+
+ if (!wlc_hw->up) {
+ if (wlc_hw->clk)
+ wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
+ chanspec);
+ wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
+ } else {
+ wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
+ wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
+
+ /* Update muting of the channel */
+ brcms_b_mute(wlc_hw, mute, 0);
}
}
-static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
- chanspec_t chanspec)
+/* switch to and initialize new band */
+static void brcms_c_setband(struct brcms_c_info *wlc,
+ uint bandunit)
{
- /* Save our copy of the chanspec */
- wlc->chanspec = chanspec;
-
- /* Set the chanspec and power limits for this locale after computing
- * any 11h local tx power constraints.
- */
- brcms_c_channel_set_chanspec(wlc->cmi, chanspec,
- brcms_c_local_constraint_qdbm(wlc));
+ wlc->band = wlc->bandstate[bandunit];
- if (wlc->stf->ss_algosel_auto)
- brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,
- chanspec);
+ if (!wlc->pub->up)
+ return;
- brcms_c_stf_ss_update(wlc, wlc->band);
+ /* wait for at least one beacon before entering sleeping state */
+ brcms_c_set_ps_ctrl(wlc);
+ /* band-specific initializations */
+ brcms_c_bsinit(wlc);
}
-void brcms_c_set_chanspec(struct brcms_c_info *wlc, chanspec_t chanspec)
+static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
{
uint bandunit;
bool switchband = false;
- chanspec_t old_chanspec = wlc->chanspec;
+ u16 old_chanspec = wlc->chanspec;
if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n",
@@ -780,8 +4050,8 @@ void brcms_c_set_chanspec(struct brcms_c_info *wlc, chanspec_t chanspec)
}
/* Switch bands if necessary */
- if (NBANDS(wlc) > 1) {
- bandunit = CHSPEC_BANDUNIT(chanspec);
+ if (wlc->pub->_nbands > 1) {
+ bandunit = chspec_bandunit(chanspec);
if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
switchband = true;
if (wlc->bandlocked) {
@@ -807,53 +4077,28 @@ void brcms_c_set_chanspec(struct brcms_c_info *wlc, chanspec_t chanspec)
brcms_c_set_phy_chanspec(wlc, chanspec);
/* init antenna selection */
- if (CHSPEC_WLC_BW(old_chanspec) != CHSPEC_WLC_BW(chanspec)) {
+ if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {
brcms_c_antsel_init(wlc->asi);
/* Fix the hardware rateset based on bw.
* Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz
*/
brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset,
- wlc->band->
- mimo_cap_40 ? CHSPEC_WLC_BW(chanspec)
- : 0);
+ wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0);
}
/* update some mac configuration since chanspec changed */
brcms_c_ucode_mac_upd(wlc);
}
-ratespec_t brcms_c_lowest_basic_rspec(struct brcms_c_info *wlc,
- wlc_rateset_t *rs)
-{
- ratespec_t lowest_basic_rspec;
- uint i;
-
- /* Use the lowest basic rate */
- lowest_basic_rspec = rs->rates[0] & BRCMS_RATE_MASK;
- for (i = 0; i < rs->count; i++) {
- if (rs->rates[i] & BRCMS_RATE_FLAG) {
- lowest_basic_rspec = rs->rates[i] & BRCMS_RATE_MASK;
- break;
- }
- }
-#if NCONF
- /* pick siso/cdd as default for OFDM (note no basic rate MCSs are supported yet) */
- if (IS_OFDM(lowest_basic_rspec)) {
- lowest_basic_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
- }
-#endif
-
- return lowest_basic_rspec;
-}
-
-/* This function changes the phytxctl for beacon based on current beacon ratespec AND txant
- * setting as per this table:
+/*
+ * This function changes the phytxctl for beacon based on current
+ * beacon ratespec AND txant setting as per this table:
* ratespec CCK ant = wlc->stf->txant
* OFDM ant = 3
*/
void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
- ratespec_t bcn_rspec)
+ u32 bcn_rspec)
{
u16 phyctl;
u16 phytxant = wlc->stf->phytxant;
@@ -863,14 +4108,16 @@ void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
if (BRCMS_PHY_11N_CAP(wlc->band))
phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec);
- phyctl = brcms_c_read_shm(wlc, M_BCN_PCTLWD);
+ phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD);
phyctl = (phyctl & ~mask) | phytxant;
- brcms_c_write_shm(wlc, M_BCN_PCTLWD, phyctl);
+ brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl);
}
-/* centralized protection config change function to simplify debugging, no consistency checking
- * this should be called only on changes to avoid overhead in periodic function
-*/
+/*
+ * centralized protection config change function to simplify debugging, no
+ * consistency checking this should be called only on changes to avoid overhead
+ * in periodic function
+ */
void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)
{
BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val);
@@ -918,13 +4165,6 @@ void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)
static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val)
{
- wlc->ht_cap.cap_info &= ~(IEEE80211_HT_CAP_SGI_20 |
- IEEE80211_HT_CAP_SGI_40);
- wlc->ht_cap.cap_info |= (val & BRCMS_N_SGI_20) ?
- IEEE80211_HT_CAP_SGI_20 : 0;
- wlc->ht_cap.cap_info |= (val & BRCMS_N_SGI_40) ?
- IEEE80211_HT_CAP_SGI_40 : 0;
-
if (wlc->pub->up) {
brcms_c_update_beacon(wlc);
brcms_c_update_probe_resp(wlc, true);
@@ -935,10 +4175,6 @@ static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
{
wlc->stf->ldpc = val;
- wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_LDPC_CODING;
- if (wlc->stf->ldpc != OFF)
- wlc->ht_cap.cap_info |= IEEE80211_HT_CAP_LDPC_CODING;
-
if (wlc->pub->up) {
brcms_c_update_beacon(wlc);
brcms_c_update_probe_resp(wlc, true);
@@ -946,262 +4182,347 @@ static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)
}
}
-/*
- * ucode, hwmac update
- * Channel dependent updates for ucode and hw
- */
-static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
+void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
+ const struct ieee80211_tx_queue_params *params,
+ bool suspend)
{
- /* enable or disable any active IBSSs depending on whether or not
- * we are on the home channel
- */
- if (wlc->home_chanspec == BRCMS_BAND_PI_RADIO_CHANSPEC) {
- if (wlc->pub->associated) {
- /* BMAC_NOTE: This is something that should be fixed in ucode inits.
- * I think that the ucode inits set up the bcn templates and shm values
- * with a bogus beacon. This should not be done in the inits. If ucode needs
- * to set up a beacon for testing, the test routines should write it down,
- * not expect the inits to populate a bogus beacon.
- */
- if (BRCMS_PHY_11N_CAP(wlc->band)) {
- brcms_c_write_shm(wlc, M_BCN_TXTSF_OFFSET,
- wlc->band->bcntsfoff);
- }
- }
- } else {
- /* disable an active IBSS if we are not on the home channel */
+ int i;
+ struct shm_acparams acp_shm;
+ u16 *shm_entry;
+
+ /* Only apply params if the core is out of reset and has clocks */
+ if (!wlc->clk) {
+ wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit,
+ __func__);
+ return;
}
- /* update the various promisc bits */
- brcms_c_mac_bcn_promisc(wlc);
- brcms_c_mac_promisc(wlc);
-}
+ memset((char *)&acp_shm, 0, sizeof(struct shm_acparams));
+ /* fill in shm ac params struct */
+ acp_shm.txop = params->txop;
+ /* convert from units of 32us to us for ucode */
+ wlc->edcf_txop[aci & 0x3] = acp_shm.txop =
+ EDCF_TXOP2USEC(acp_shm.txop);
+ acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
-static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
- chanspec_t chanspec)
-{
- wlc_rateset_t default_rateset;
- uint parkband;
- uint i, band_order[2];
+ if (aci == AC_VI && acp_shm.txop == 0
+ && acp_shm.aifs < EDCF_AIFSN_MAX)
+ acp_shm.aifs++;
- BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
- /*
- * We might have been bandlocked during down and the chip power-cycled (hibernate).
- * figure out the right band to park on
- */
- if (wlc->bandlocked || NBANDS(wlc) == 1) {
- /* updated in brcms_c_bandlock() */
- parkband = wlc->band->bandunit;
- band_order[0] = band_order[1] = parkband;
+ if (acp_shm.aifs < EDCF_AIFSN_MIN
+ || acp_shm.aifs > EDCF_AIFSN_MAX) {
+ wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad "
+ "aifs %d\n", wlc->pub->unit, acp_shm.aifs);
} else {
- /* park on the band of the specified chanspec */
- parkband = CHSPEC_BANDUNIT(chanspec);
+ acp_shm.cwmin = params->cw_min;
+ acp_shm.cwmax = params->cw_max;
+ acp_shm.cwcur = acp_shm.cwmin;
+ acp_shm.bslots =
+ R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur;
+ acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
+ /* Indicate the new params to the ucode */
+ acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO +
+ wme_ac2fifo[aci] *
+ M_EDCF_QLEN +
+ M_EDCF_STATUS_OFF));
+ acp_shm.status |= WME_STATUS_NEWAC;
- /* order so that parkband initialize last */
- band_order[0] = parkband ^ 1;
- band_order[1] = parkband;
+ /* Fill in shm acparam table */
+ shm_entry = (u16 *) &acp_shm;
+ for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2)
+ brcms_b_write_shm(wlc->hw,
+ M_EDCF_QINFO +
+ wme_ac2fifo[aci] * M_EDCF_QLEN + i,
+ *shm_entry++);
}
- /* make each band operational, software state init */
- for (i = 0; i < NBANDS(wlc); i++) {
- uint j = band_order[i];
+ if (suspend) {
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_enable_mac(wlc);
+ }
+}
- wlc->band = wlc->bandstate[j];
+void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+{
+ u16 aci;
+ int i_ac;
+ struct ieee80211_tx_queue_params txq_pars;
+ static const struct edcf_acparam default_edcf_acparams[] = {
+ {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA},
+ {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA},
+ {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA},
+ {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA}
+ }; /* ucode needs these parameters during its initialization */
+ const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
- brcms_default_rateset(wlc, &default_rateset);
+ for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
+ /* find out which ac this set of params applies to */
+ aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
- /* fill in hw_rate */
- brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,
- false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
- (bool) N_ENAB(wlc->pub));
+ /* fill in shm ac params struct */
+ txq_pars.txop = edcf_acp->TXOP;
+ txq_pars.aifs = edcf_acp->ACI;
- /* init basic rate lookup */
- brcms_c_rate_lookup_init(wlc, &default_rateset);
+ /* CWmin = 2^(ECWmin) - 1 */
+ txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
+ /* CWmax = 2^(ECWmax) - 1 */
+ txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
+ >> EDCF_ECWMAX_SHIFT);
+ brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend);
}
- /* sync up phy/radio chanspec */
- brcms_c_set_phy_chanspec(wlc, chanspec);
+ if (suspend) {
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_enable_mac(wlc);
+ }
}
-/* band-specific init */
-static void brcms_c_bsinit(struct brcms_c_info *wlc)
+/* maintain LED behavior in down state */
+static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
{
- BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
- wlc->pub->unit, wlc->band->bandunit);
+ /*
+ * maintain LEDs while in down state, turn on sbclk if
+ * not available yet. Turn on sbclk if necessary
+ */
+ brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP);
+ brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP);
+}
- /* write ucode ACK/CTS rate table */
- brcms_c_set_ratetable(wlc);
+static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
+{
+ /* Don't start the timer if HWRADIO feature is disabled */
+ if (wlc->radio_monitor)
+ return;
- /* update some band specific mac configuration */
- brcms_c_ucode_mac_upd(wlc);
+ wlc->radio_monitor = true;
+ brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON);
+ brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
+}
- /* init antenna selection */
- brcms_c_antsel_init(wlc->asi);
+static void brcms_c_radio_disable(struct brcms_c_info *wlc)
+{
+ if (!wlc->pub->up) {
+ brcms_c_down_led_upd(wlc);
+ return;
+ }
+ brcms_c_radio_monitor_start(wlc);
+ brcms_down(wlc->wl);
}
-/* switch to and initialize new band */
-static void brcms_c_setband(struct brcms_c_info *wlc,
- uint bandunit)
+static void brcms_c_radio_enable(struct brcms_c_info *wlc)
{
- int idx;
- struct brcms_bss_cfg *cfg;
+ if (wlc->pub->up)
+ return;
- wlc->band = wlc->bandstate[bandunit];
+ if (brcms_deviceremoved(wlc))
+ return;
- if (!wlc->pub->up)
+ brcms_up(wlc->wl);
+}
+
+static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
+{
+ if (!wlc->radio_monitor)
+ return true;
+
+ wlc->radio_monitor = false;
+ brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON);
+ return brcms_del_timer(wlc->radio_timer);
+}
+
+/* read hwdisable state and propagate to wlc flag */
+static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
+{
+ if (wlc->pub->hw_off)
return;
- /* wait for at least one beacon before entering sleeping state */
- for (idx = 0; idx < BRCMS_MAXBSSCFG; idx++) {
- cfg = wlc->bsscfg[idx];
- if (cfg && BSSCFG_STA(cfg) && cfg->associated)
- cfg->PMawakebcn = true;
- }
- brcms_c_set_ps_ctrl(wlc);
+ if (brcms_b_radio_read_hwdisabled(wlc->hw))
+ mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
+ else
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
+}
- /* band-specific initializations */
- brcms_c_bsinit(wlc);
+/*
+ * centralized radio disable/enable function,
+ * invoke radio enable/disable after updating hwradio status
+ */
+static void brcms_c_radio_upd(struct brcms_c_info *wlc)
+{
+ if (wlc->pub->radio_disabled)
+ brcms_c_radio_disable(wlc);
+ else
+ brcms_c_radio_enable(wlc);
}
-/* Initialize a WME Parameter Info Element with default STA parameters from WMM Spec, Table 12 */
-void
-brcms_c_wme_initparams_sta(struct brcms_c_info *wlc, struct wme_param_ie *pe)
-{
- static const struct wme_param_ie stadef = {
- WME_OUI,
- WME_TYPE,
- WME_SUBTYPE_PARAM_IE,
- WME_VER,
- 0,
- 0,
- {
- {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA,
- cpu_to_le16(EDCF_AC_BE_TXOP_STA)},
- {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA,
- cpu_to_le16(EDCF_AC_BK_TXOP_STA)},
- {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA,
- cpu_to_le16(EDCF_AC_VI_TXOP_STA)},
- {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA,
- cpu_to_le16(EDCF_AC_VO_TXOP_STA)}
- }
- };
- memcpy(pe, &stadef, sizeof(*pe));
+/* update hwradio status and return it */
+bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
+{
+ brcms_c_radio_hwdisable_upd(wlc);
+
+ return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?
+ true : false;
}
-void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
- const struct ieee80211_tx_queue_params *params,
- bool suspend)
+/* periodical query hw radio button while driver is "down" */
+static void brcms_c_radio_timer(void *arg)
{
- int i;
- struct shm_acparams acp_shm;
- u16 *shm_entry;
+ struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
- /* Only apply params if the core is out of reset and has clocks */
- if (!wlc->clk) {
- wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit,
- __func__);
+ if (brcms_deviceremoved(wlc)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
+ __func__);
+ brcms_down(wlc->wl);
return;
}
- do {
- memset((char *)&acp_shm, 0, sizeof(struct shm_acparams));
- /* fill in shm ac params struct */
- acp_shm.txop = le16_to_cpu(params->txop);
- /* convert from units of 32us to us for ucode */
- wlc->edcf_txop[aci & 0x3] = acp_shm.txop =
- EDCF_TXOP2USEC(acp_shm.txop);
- acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
-
- if (aci == AC_VI && acp_shm.txop == 0
- && acp_shm.aifs < EDCF_AIFSN_MAX)
- acp_shm.aifs++;
-
- if (acp_shm.aifs < EDCF_AIFSN_MIN
- || acp_shm.aifs > EDCF_AIFSN_MAX) {
- wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad "
- "aifs %d\n", wlc->pub->unit, acp_shm.aifs);
- continue;
- }
+ /* cap mpc off count */
+ if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
+ wlc->mpc_offcnt++;
- acp_shm.cwmin = params->cw_min;
- acp_shm.cwmax = params->cw_max;
- acp_shm.cwcur = acp_shm.cwmin;
- acp_shm.bslots =
- R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur;
- acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;
- /* Indicate the new params to the ucode */
- acp_shm.status = brcms_c_read_shm(wlc, (M_EDCF_QINFO +
- wme_shmemacindex(aci) *
- M_EDCF_QLEN +
- M_EDCF_STATUS_OFF));
- acp_shm.status |= WME_STATUS_NEWAC;
+ brcms_c_radio_hwdisable_upd(wlc);
+ brcms_c_radio_upd(wlc);
+}
- /* Fill in shm acparam table */
- shm_entry = (u16 *) &acp_shm;
- for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2)
- brcms_c_write_shm(wlc,
- M_EDCF_QINFO +
- wme_shmemacindex(aci) * M_EDCF_QLEN + i,
- *shm_entry++);
+/* common low-level watchdog code */
+static void brcms_b_watchdog(void *arg)
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+ struct brcms_hardware *wlc_hw = wlc->hw;
- } while (0);
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
- if (suspend)
- brcms_c_suspend_mac_and_wait(wlc);
+ if (!wlc_hw->up)
+ return;
- if (suspend)
- brcms_c_enable_mac(wlc);
+ /* increment second count */
+ wlc_hw->now++;
+
+ /* Check for FIFO error interrupts */
+ brcms_b_fifoerrors(wlc_hw);
+ /* make sure RX dma has buffers */
+ dma_rxfill(wlc->hw->di[RX_FIFO]);
+
+ wlc_phy_watchdog(wlc_hw->band->pi);
}
-void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
{
- u16 aci;
- int i_ac;
- struct edcf_acparam *edcf_acp;
+ bool mpc_radio, radio_state;
- struct ieee80211_tx_queue_params txq_pars;
- struct ieee80211_tx_queue_params *params = &txq_pars;
+ /*
+ * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
+ * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
+ * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
+ * the radio is going down.
+ */
+ if (!wlc->mpc) {
+ if (!wlc->pub->radio_disabled)
+ return;
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
+ brcms_c_radio_upd(wlc);
+ if (!wlc->pub->radio_disabled)
+ brcms_c_radio_monitor_stop(wlc);
+ return;
+ }
/*
- * AP uses AC params from wme_param_ie_ap.
- * AP advertises AC params from wme_param_ie.
- * STA uses AC params from wme_param_ie.
+ * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
+ * wlc->pub->radio_disabled to go ON, always call radio_upd
+ * synchronously to go OFF, postpone radio_upd to later when
+ * context is safe(e.g. watchdog)
*/
+ radio_state =
+ (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
+ ON);
+ mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
- edcf_acp = (struct edcf_acparam *) &wlc->wme_param_ie.acparam[0];
+ if (radio_state == ON && mpc_radio == OFF)
+ wlc->mpc_delay_off = wlc->mpc_dlycnt;
+ else if (radio_state == OFF && mpc_radio == ON) {
+ mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
+ brcms_c_radio_upd(wlc);
+ if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
+ wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
+ else
+ wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+ }
+ /*
+ * Below logic is meant to capture the transition from mpc off
+ * to mpc on for reasons other than wlc->mpc_delay_off keeping
+ * the mpc off. In that case reset wlc->mpc_delay_off to
+ * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
+ */
+ if ((wlc->prev_non_delay_mpc == false) &&
+ (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
+ wlc->mpc_delay_off = wlc->mpc_dlycnt;
- for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
- /* find out which ac this set of params applies to */
- aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
+ wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
+}
- /* fill in shm ac params struct */
- params->txop = edcf_acp->TXOP;
- params->aifs = edcf_acp->ACI;
+/* common watchdog code */
+static void brcms_c_watchdog(void *arg)
+{
+ struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
- /* CWmin = 2^(ECWmin) - 1 */
- params->cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
- /* CWmax = 2^(ECWmax) - 1 */
- params->cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
- >> EDCF_ECWMAX_SHIFT);
- brcms_c_wme_setparams(wlc, aci, params, suspend);
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ if (!wlc->pub->up)
+ return;
+
+ if (brcms_deviceremoved(wlc)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return;
}
- if (suspend)
- brcms_c_suspend_mac_and_wait(wlc);
+ /* increment second count */
+ wlc->pub->now++;
- if (AP_ENAB(wlc->pub) && WME_ENAB(wlc->pub)) {
- brcms_c_update_beacon(wlc);
- brcms_c_update_probe_resp(wlc, false);
+ /* delay radio disable */
+ if (wlc->mpc_delay_off) {
+ if (--wlc->mpc_delay_off == 0) {
+ mboolset(wlc->pub->radio_disabled,
+ WL_RADIO_MPC_DISABLE);
+ if (wlc->mpc && brcms_c_ismpc(wlc))
+ wlc->mpc_offcnt = 0;
+ }
}
- if (suspend)
- brcms_c_enable_mac(wlc);
+ /* mpc sync */
+ brcms_c_radio_mpc_upd(wlc);
+ /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
+ brcms_c_radio_hwdisable_upd(wlc);
+ brcms_c_radio_upd(wlc);
+ /* if radio is disable, driver may be down, quit here */
+ if (wlc->pub->radio_disabled)
+ return;
+
+ brcms_b_watchdog(wlc);
+
+ /*
+ * occasionally sample mac stat counters to
+ * detect 16-bit counter wrap
+ */
+ if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
+ brcms_c_statsupd(wlc);
+ if (BRCMS_ISNPHY(wlc->band) &&
+ ((wlc->pub->now - wlc->tempsense_lasttime) >=
+ BRCMS_TEMPSENSE_PERIOD)) {
+ wlc->tempsense_lasttime = wlc->pub->now;
+ brcms_c_tempsense_upd(wlc);
+ }
+}
+
+static void brcms_c_watchdog_by_timer(void *arg)
+{
+ brcms_c_watchdog(arg);
}
-bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
+static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
{
wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
wlc, "watchdog");
@@ -1229,14 +4550,12 @@ bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
* Initialize brcms_c_info default values ...
* may get overrides later in this function
*/
-void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
+static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
{
int i;
- /* Assume the device is there until proven otherwise */
- wlc->device_present = true;
/* Save our copy of the chanspec */
- wlc->chanspec = CH20MHZ_CHSPEC(1);
+ wlc->chanspec = ch20mhz_chspec(1);
/* various 802.11g modes */
wlc->shortslot = false;
@@ -1277,44 +4596,14 @@ void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
wlc->SRL = RETRY_SHORT_DEF;
wlc->LRL = RETRY_LONG_DEF;
- /* Set flag to indicate that hw keys should be used when available. */
- wlc->wsec_swkeys = false;
-
- /* init the 4 static WEP default keys */
- for (i = 0; i < WSEC_MAX_DEFAULT_KEYS; i++) {
- wlc->wsec_keys[i] = wlc->wsec_def_keys[i];
- wlc->wsec_keys[i]->idx = (u8) i;
- }
-
/* WME QoS mode is Auto by default */
- wlc->pub->_wme = AUTO;
-
-#ifdef BCMSDIODEV_ENABLED
- wlc->pub->_priofc = true; /* enable priority flow control for sdio dongle */
-#endif
-
wlc->pub->_ampdu = AMPDU_AGG_HOST;
wlc->pub->bcmerror = 0;
- wlc->pub->_coex = ON;
/* initialize mpc delay */
wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
}
-static bool brcms_c_state_bmac_sync(struct brcms_c_info *wlc)
-{
- struct brcms_b_state state_bmac;
-
- if (brcms_b_state_get(wlc->hw, &state_bmac) != 0)
- return false;
-
- wlc->machwcap = state_bmac.machwcap;
- brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR,
- (s8) state_bmac.preamble_ovr);
-
- return true;
-}
-
static uint brcms_c_attach_module(struct brcms_c_info *wlc)
{
uint err = 0;
@@ -1347,262 +4636,325 @@ static uint brcms_c_attach_module(struct brcms_c_info *wlc)
return err;
}
-struct brcms_pub *brcms_c_pub(void *wlc)
+struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc)
{
- return ((struct brcms_c_info *) wlc)->pub;
+ return wlc->pub;
}
-#define CHIP_SUPPORTS_11N(wlc) 1
-
-/*
- * The common driver entry routine. Error codes should be unique
+/* low level attach
+ * run backplane attach, init nvram
+ * run phy attach
+ * initialize software state for each core and band
+ * put the whole chip in reset(driver down state), no clock
*/
-void *brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
- bool piomode, void *regsva, uint bustype, void *btparam,
- uint *perr)
+static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device,
+ uint unit, bool piomode, void __iomem *regsva,
+ struct pci_dev *btparam)
{
- struct brcms_c_info *wlc;
+ struct brcms_hardware *wlc_hw;
+ struct d11regs __iomem *regs;
+ char *macaddr = NULL;
uint err = 0;
uint j;
- struct brcms_pub *pub;
- uint n_disabled;
+ bool wme = false;
+ struct shared_phy_params sha_params;
+ struct wiphy *wiphy = wlc->wiphy;
- /* allocate struct brcms_c_info state and its substructures */
- wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device);
- if (wlc == NULL)
- goto fail;
- wlc->wiphy = wl->wiphy;
- pub = wlc->pub;
+ BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor,
+ device);
-#if defined(BCMDBG)
- wlc_info_dbg = wlc;
-#endif
+ wme = true;
- wlc->band = wlc->bandstate[0];
- wlc->core = wlc->corestate;
- wlc->wl = wl;
- pub->unit = unit;
- pub->_piomode = piomode;
- wlc->bandinit_pending = false;
+ wlc_hw = wlc->hw;
+ wlc_hw->wlc = wlc;
+ wlc_hw->unit = unit;
+ wlc_hw->band = wlc_hw->bandstate[0];
+ wlc_hw->_piomode = piomode;
- /* populate struct brcms_c_info with default values */
- brcms_c_info_init(wlc, unit);
-
- /* update sta/ap related parameters */
- brcms_c_ap_upd(wlc);
-
- /* 11n_disable nvram */
- n_disabled = getintvar(pub->vars, "11n_disable");
+ /* populate struct brcms_hardware with default values */
+ brcms_b_info_init(wlc_hw);
/*
- * low level attach steps(all hw accesses go
- * inside, no more in rest of the attach)
- */
- err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva,
- bustype, btparam);
- if (err)
- goto fail;
-
- /* for some states, due to different info pointer(e,g, wlc, wlc_hw) or master/slave split,
- * HIGH driver(both monolithic and HIGH_ONLY) needs to sync states FROM BMAC portion driver
+ * Do the hardware portion of the attach. Also initialize software
+ * state that depends on the particular hardware we are running.
*/
- if (!brcms_c_state_bmac_sync(wlc)) {
- err = 20;
+ wlc_hw->sih = ai_attach(regsva, btparam);
+ if (wlc_hw->sih == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
+ unit);
+ err = 11;
goto fail;
}
- pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
-
- /* propagate *vars* from BMAC driver to high driver */
- brcms_b_copyfrom_vars(wlc->hw, &pub->vars, &wlc->vars_size);
-
-
- /* set maximum allowed duty cycle */
- wlc->tx_duty_cycle_ofdm =
- (u16) getintvar(pub->vars, "tx_duty_cycle_ofdm");
- wlc->tx_duty_cycle_cck =
- (u16) getintvar(pub->vars, "tx_duty_cycle_cck");
-
- brcms_c_stf_phy_chain_calc(wlc);
-
- /* txchain 1: txant 0, txchain 2: txant 1 */
- if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
- wlc->stf->txant = wlc->stf->hw_txchain - 1;
-
- /* push to BMAC driver */
- wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
- wlc->stf->hw_rxchain);
-
- /* pull up some info resulting from the low attach */
- {
- int i;
- for (i = 0; i < NFIFO; i++)
- wlc->core->txavail[i] = wlc->hw->txavail[i];
+ /* verify again the device is supported */
+ if (!brcms_c_chipmatch(vendor, device)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
+ "vendor/device (0x%x/0x%x)\n",
+ unit, vendor, device);
+ err = 12;
+ goto fail;
}
- brcms_b_hw_etheraddr(wlc->hw, wlc->perm_etheraddr);
-
- memcpy(&pub->cur_etheraddr, &wlc->perm_etheraddr, ETH_ALEN);
-
- for (j = 0; j < NBANDS(wlc); j++) {
- /* Use band 1 for single band 11a */
- if (IS_SINGLEBAND_5G(wlc->deviceid))
- j = BAND_5G_INDEX;
-
- wlc->band = wlc->bandstate[j];
-
- if (!brcms_c_attach_stf_ant_init(wlc)) {
- err = 24;
- goto fail;
- }
+ wlc_hw->vendorid = vendor;
+ wlc_hw->deviceid = device;
- /* default contention windows size limits */
- wlc->band->CWmin = APHY_CWMIN;
- wlc->band->CWmax = PHY_CWMAX;
+ /* set bar0 window to point at D11 core */
+ wlc_hw->regs = (struct d11regs __iomem *)
+ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
+ wlc_hw->corerev = ai_corerev(wlc_hw->sih);
- /* init gmode value */
- if (BAND_2G(wlc->band->bandtype)) {
- wlc->band->gmode = GMODE_AUTO;
- brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
- wlc->band->gmode);
- }
+ regs = wlc_hw->regs;
- /* init _n_enab supported mode */
- if (BRCMS_PHY_11N_CAP(wlc->band) && CHIP_SUPPORTS_11N(wlc)) {
- if (n_disabled & WLFEATURE_DISABLE_11N) {
- pub->_n_enab = OFF;
- brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
- OFF);
- } else {
- pub->_n_enab = SUPPORT_11N;
- brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
- ((pub->_n_enab ==
- SUPPORT_11N) ? WL_11N_2x2 :
- WL_11N_3x3));
- }
- }
+ wlc->regs = wlc_hw->regs;
- /* init per-band default rateset, depend on band->gmode */
- brcms_default_rateset(wlc, &wlc->band->defrateset);
-
- /* fill in hw_rateset (used early by BRCM_SET_RATESET) */
- brcms_c_rateset_filter(&wlc->band->defrateset,
- &wlc->band->hw_rateset, false,
- BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
- (bool) N_ENAB(wlc->pub));
+ /* validate chip, chiprev and corerev */
+ if (!brcms_c_isgoodchip(wlc_hw)) {
+ err = 13;
+ goto fail;
}
- /* update antenna config due to wlc->stf->txant/txchain/ant_rx_ovr change */
- brcms_c_stf_phy_txant_upd(wlc);
+ /* initialize power control registers */
+ ai_clkctl_init(wlc_hw->sih);
- /* attach each modules */
- err = brcms_c_attach_module(wlc);
- if (err != 0)
- goto fail;
+ /* request fastclock and force fastclock for the rest of attach
+ * bring the d11 core out of reset.
+ * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk
+ * is still false; But it will be called again inside wlc_corereset,
+ * after d11 is out of reset.
+ */
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
- if (!brcms_c_timers_init(wlc, unit)) {
- wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
- __func__);
- err = 32;
+ if (!brcms_b_validate_chip_access(wlc_hw)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
+ "failed\n", unit);
+ err = 14;
goto fail;
}
- /* depend on rateset, gmode */
- wlc->cmi = brcms_c_channel_mgr_attach(wlc);
- if (!wlc->cmi) {
- wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
- "\n", unit, __func__);
- err = 33;
+ /* get the board rev, used just below */
+ j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV);
+ /* promote srom boardrev of 0xFF to 1 */
+ if (j == BOARDREV_PROMOTABLE)
+ j = BOARDREV_PROMOTED;
+ wlc_hw->boardrev = (u16) j;
+ if (!brcms_c_validboardtype(wlc_hw)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
+ "board type (0x%x)" " or revision level (0x%x)\n",
+ unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
+ err = 15;
goto fail;
}
+ wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV);
+ wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih,
+ BRCMS_SROM_BOARDFLAGS);
+ wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih,
+ BRCMS_SROM_BOARDFLAGS2);
- /* init default when all parameters are ready, i.e. ->rateset */
- brcms_c_bss_default_init(wlc);
+ if (wlc_hw->boardflags & BFL_NOPLLDOWN)
+ brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
- /*
- * Complete the wlc default state initializations..
+ /* check device id(srom, nvram etc.) to set bands */
+ if (wlc_hw->deviceid == BCM43224_D11N_ID ||
+ wlc_hw->deviceid == BCM43224_D11N_ID_VEN1)
+ /* Dualband boards */
+ wlc_hw->_nbands = 2;
+ else
+ wlc_hw->_nbands = 1;
+
+ if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
+ wlc_hw->_nbands = 1;
+
+ /* BMAC_NOTE: remove init of pub values when brcms_c_attach()
+ * unconditionally does the init of these values
*/
+ wlc->vendorid = wlc_hw->vendorid;
+ wlc->deviceid = wlc_hw->deviceid;
+ wlc->pub->sih = wlc_hw->sih;
+ wlc->pub->corerev = wlc_hw->corerev;
+ wlc->pub->sromrev = wlc_hw->sromrev;
+ wlc->pub->boardrev = wlc_hw->boardrev;
+ wlc->pub->boardflags = wlc_hw->boardflags;
+ wlc->pub->boardflags2 = wlc_hw->boardflags2;
+ wlc->pub->_nbands = wlc_hw->_nbands;
+
+ wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
+
+ if (wlc_hw->physhim == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
+ "failed\n", unit);
+ err = 25;
+ goto fail;
+ }
- /* allocate our initial queue */
- wlc->pkt_queue = brcms_c_txq_alloc(wlc);
- if (wlc->pkt_queue == NULL) {
- wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
- unit, __func__);
- err = 100;
+ /* pass all the parameters to wlc_phy_shared_attach in one struct */
+ sha_params.sih = wlc_hw->sih;
+ sha_params.physhim = wlc_hw->physhim;
+ sha_params.unit = unit;
+ sha_params.corerev = wlc_hw->corerev;
+ sha_params.vid = wlc_hw->vendorid;
+ sha_params.did = wlc_hw->deviceid;
+ sha_params.chip = wlc_hw->sih->chip;
+ sha_params.chiprev = wlc_hw->sih->chiprev;
+ sha_params.chippkg = wlc_hw->sih->chippkg;
+ sha_params.sromrev = wlc_hw->sromrev;
+ sha_params.boardtype = wlc_hw->sih->boardtype;
+ sha_params.boardrev = wlc_hw->boardrev;
+ sha_params.boardvendor = wlc_hw->sih->boardvendor;
+ sha_params.boardflags = wlc_hw->boardflags;
+ sha_params.boardflags2 = wlc_hw->boardflags2;
+ sha_params.buscorerev = wlc_hw->sih->buscorerev;
+
+ /* alloc and save pointer to shared phy state area */
+ wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
+ if (!wlc_hw->phy_sh) {
+ err = 16;
goto fail;
}
- wlc->bsscfg[0] = wlc->cfg;
- wlc->cfg->_idx = 0;
- wlc->cfg->wlc = wlc;
- pub->txmaxpkts = MAXTXPKTS;
+ /* initialize software state for each core and band */
+ for (j = 0; j < wlc_hw->_nbands; j++) {
+ /*
+ * band0 is always 2.4Ghz
+ * band1, if present, is 5Ghz
+ */
- brcms_c_wme_initparams_sta(wlc, &wlc->wme_param_ie);
+ brcms_c_setxband(wlc_hw, j);
+
+ wlc_hw->band->bandunit = j;
+ wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
+ wlc->band->bandunit = j;
+ wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
+ wlc->core->coreidx = ai_coreidx(wlc_hw->sih);
+
+ wlc_hw->machwcap = R_REG(&regs->machwcap);
+ wlc_hw->machwcap_backup = wlc_hw->machwcap;
+
+ /* init tx fifo size */
+ wlc_hw->xmtfifo_sz =
+ xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
+
+ /* Get a phy for this band */
+ wlc_hw->band->pi =
+ wlc_phy_attach(wlc_hw->phy_sh, regs,
+ wlc_hw->band->bandtype,
+ wlc->wiphy);
+ if (wlc_hw->band->pi == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
+ "attach failed\n", unit);
+ err = 17;
+ goto fail;
+ }
- wlc->mimoft = FT_HT;
- wlc->ht_cap.cap_info = HT_CAP;
- if (HT_ENAB(wlc->pub))
- wlc->stf->ldpc = AUTO;
+ wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
+
+ wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
+ &wlc_hw->band->phyrev,
+ &wlc_hw->band->radioid,
+ &wlc_hw->band->radiorev);
+ wlc_hw->band->abgphy_encore =
+ wlc_phy_get_encore(wlc_hw->band->pi);
+ wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
+ wlc_hw->band->core_flags =
+ wlc_phy_get_coreflags(wlc_hw->band->pi);
+
+ /* verify good phy_type & supported phy revision */
+ if (BRCMS_ISNPHY(wlc_hw->band)) {
+ if (NCONF_HAS(wlc_hw->band->phyrev))
+ goto good_phy;
+ else
+ goto bad_phy;
+ } else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
+ if (LCNCONF_HAS(wlc_hw->band->phyrev))
+ goto good_phy;
+ else
+ goto bad_phy;
+ } else {
+ bad_phy:
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
+ "phy type/rev (%d/%d)\n", unit,
+ wlc_hw->band->phytype, wlc_hw->band->phyrev);
+ err = 18;
+ goto fail;
+ }
- wlc->mimo_40txbw = AUTO;
- wlc->ofdm_40txbw = AUTO;
- wlc->cck_40txbw = AUTO;
- brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
+ good_phy:
+ /*
+ * BMAC_NOTE: wlc->band->pi should not be set below and should
+ * be done in the high level attach. However we can not make
+ * that change until all low level access is changed to
+ * wlc_hw->band->pi. Instead do the wlc->band->pi init below,
+ * keeping wlc_hw->band->pi as well for incremental update of
+ * low level fns, and cut over low only init when all fns
+ * updated.
+ */
+ wlc->band->pi = wlc_hw->band->pi;
+ wlc->band->phytype = wlc_hw->band->phytype;
+ wlc->band->phyrev = wlc_hw->band->phyrev;
+ wlc->band->radioid = wlc_hw->band->radioid;
+ wlc->band->radiorev = wlc_hw->band->radiorev;
- /* Set default values of SGI */
- if (BRCMS_SGI_CAP_PHY(wlc)) {
- brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
- BRCMS_N_SGI_40));
- wlc->sgi_tx = AUTO;
- } else if (BRCMS_ISSSLPNPHY(wlc->band)) {
- brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
- BRCMS_N_SGI_40));
- wlc->sgi_tx = AUTO;
- } else {
- brcms_c_ht_update_sgi_rx(wlc, 0);
- wlc->sgi_tx = OFF;
+ /* default contention windows size limits */
+ wlc_hw->band->CWmin = APHY_CWMIN;
+ wlc_hw->band->CWmax = PHY_CWMAX;
+
+ if (!brcms_b_attach_dmapio(wlc, j, wme)) {
+ err = 19;
+ goto fail;
+ }
}
- /* *******nvram 11n config overrides Start ********* */
+ /* disable core to match driver "down" state */
+ brcms_c_coredisable(wlc_hw);
- /* apply the sgi override from nvram conf */
- if (n_disabled & WLFEATURE_DISABLE_11N_SGI_TX)
- wlc->sgi_tx = OFF;
+ /* Match driver "down" state */
+ ai_pci_down(wlc_hw->sih);
- if (n_disabled & WLFEATURE_DISABLE_11N_SGI_RX)
- brcms_c_ht_update_sgi_rx(wlc, 0);
+ /* register sb interrupt callback functions */
+ ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff,
+ (void *)brcms_c_wlintrsrestore, NULL, wlc);
- /* apply the stbc override from nvram conf */
- if (n_disabled & WLFEATURE_DISABLE_11N_STBC_TX) {
- wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF;
- wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF;
- wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_TX_STBC;
- }
- if (n_disabled & WLFEATURE_DISABLE_11N_STBC_RX)
- brcms_c_stf_stbc_rx_set(wlc, HT_CAP_RX_STBC_NO);
+ /* turn off pll and xtal to match driver "down" state */
+ brcms_b_xtal(wlc_hw, OFF);
- /* apply the GF override from nvram conf */
- if (n_disabled & WLFEATURE_DISABLE_11N_GF)
- wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_GRN_FLD;
+ /* *******************************************************************
+ * The hardware is in the DOWN state at this point. D11 core
+ * or cores are in reset with clocks off, and the board PLLs
+ * are off if possible.
+ *
+ * Beyond this point, wlc->sbclk == false and chip registers
+ * should not be touched.
+ *********************************************************************
+ */
- /* initialize radio_mpc_disable according to wlc->mpc */
- brcms_c_radio_mpc_upd(wlc);
- brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
+ /* init etheraddr state variables */
+ macaddr = brcms_c_get_macaddr(wlc_hw);
+ if (macaddr == NULL) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
+ unit);
+ err = 21;
+ goto fail;
+ }
+ if (!mac_pton(macaddr, wlc_hw->etheraddr) ||
+ is_broadcast_ether_addr(wlc_hw->etheraddr) ||
+ is_zero_ether_addr(wlc_hw->etheraddr)) {
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
+ unit, macaddr);
+ err = 22;
+ goto fail;
+ }
- if (perr)
- *perr = 0;
+ BCMMSG(wlc->wiphy,
+ "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
+ wlc_hw->deviceid, wlc_hw->_nbands,
+ wlc_hw->sih->boardtype, macaddr);
- return (void *)wlc;
+ return err;
fail:
- wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
- unit, __func__, err);
- if (wlc)
- brcms_c_detach(wlc);
-
- if (perr)
- *perr = err;
- return NULL;
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
+ err);
+ return err;
}
static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
@@ -1620,14 +4972,17 @@ static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc)
} else {
s8 gain, fract;
/* Older sroms specified gain in whole dbm only. In order
- * be able to specify qdbm granularity and remain backward compatible
- * the whole dbms are now encoded in only low 6 bits and remaining qdbms
- * are encoded in the hi 2 bits. 6 bit signed number ranges from
- * -32 - 31. Examples: 0x1 = 1 db,
+ * be able to specify qdbm granularity and remain backward
+ * compatible the whole dbms are now encoded in only
+ * low 6 bits and remaining qdbms are encoded in the hi 2 bits.
+ * 6 bit signed number ranges from -32 - 31.
+ *
+ * Examples:
+ * 0x1 = 1 db,
* 0xc1 = 1.75 db (1 + 3 quarters),
* 0x3f = -1 (-1 + 0 quarters),
- * 0x7f = -.75 (-1 in low 6 bits + 1 quarters in hi 2 bits) = -3 qdbm.
- * 0xbf = -.50 (-1 in low 6 bits + 2 quarters in hi 2 bits) = -2 qdbm.
+ * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm.
+ * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm.
*/
gain = wlc->band->antgain & 0x3f;
gain <<= 2; /* Sign extend */
@@ -1641,18 +4996,18 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
{
int aa;
uint unit;
- char *vars;
int bandtype;
+ struct si_pub *sih = wlc->hw->sih;
unit = wlc->pub->unit;
- vars = wlc->pub->vars;
bandtype = wlc->band->bandtype;
/* get antennas available */
- aa = (s8) getintvar(vars, (BAND_5G(bandtype) ? "aa5g" : "aa2g"));
- if (aa == 0)
- aa = (s8) getintvar(vars,
- (BAND_5G(bandtype) ? "aa1" : "aa0"));
+ if (bandtype == BRCM_BAND_5G)
+ aa = (s8) getintvar(sih, BRCMS_SROM_AA5G);
+ else
+ aa = (s8) getintvar(sih, BRCMS_SROM_AA2G);
+
if ((aa < 1) || (aa > 15)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
" srom (0x%x), using 3\n", unit, __func__, aa);
@@ -1670,23 +5025,129 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
}
/* Compute Antenna Gain */
- wlc->band->antgain =
- (s8) getintvar(vars, (BAND_5G(bandtype) ? "ag1" : "ag0"));
+ if (bandtype == BRCM_BAND_5G)
+ wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1);
+ else
+ wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0);
+
brcms_c_attach_antgain_init(wlc);
return true;
}
+static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
+{
+ u16 chanspec;
+ struct brcms_band *band;
+ struct brcms_bss_info *bi = wlc->default_bss;
+
+ /* init default and target BSS with some sane initial values */
+ memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
+ bi->beacon_period = BEACON_INTERVAL_DEFAULT;
+
+ /* fill the default channel as the first valid channel
+ * starting from the 2G channels
+ */
+ chanspec = ch20mhz_chspec(1);
+ wlc->home_chanspec = bi->chanspec = chanspec;
+
+ /* find the band of our default channel */
+ band = wlc->band;
+ if (wlc->pub->_nbands > 1 &&
+ band->bandunit != chspec_bandunit(chanspec))
+ band = wlc->bandstate[OTHERBANDUNIT(wlc)];
+
+ /* init bss rates to the band specific default rate set */
+ brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
+ band->bandtype, false, BRCMS_RATE_MASK_FULL,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N),
+ brcms_chspec_bw(chanspec), wlc->stf->txstreams);
+
+ if (wlc->pub->_n_enab & SUPPORT_11N)
+ bi->flags |= BRCMS_BSS_HT;
+}
+
+static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
+{
+ struct brcms_txq_info *qi, *p;
+
+ qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
+ if (qi != NULL) {
+ /*
+ * Have enough room for control packets along with HI watermark
+ * Also, add room to txq for total psq packets if all the SCBs
+ * leave PS mode. The watermark for flowcontrol to OS packets
+ * will remain the same
+ */
+ brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
+ 2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT);
+
+ /* add this queue to the the global list */
+ p = wlc->tx_queues;
+ if (p == NULL) {
+ wlc->tx_queues = qi;
+ } else {
+ while (p->next != NULL)
+ p = p->next;
+ p->next = qi;
+ }
+ }
+ return qi;
+}
+
+static void brcms_c_txq_free(struct brcms_c_info *wlc,
+ struct brcms_txq_info *qi)
+{
+ struct brcms_txq_info *p;
+
+ if (qi == NULL)
+ return;
+
+ /* remove the queue from the linked list */
+ p = wlc->tx_queues;
+ if (p == qi)
+ wlc->tx_queues = p->next;
+ else {
+ while (p != NULL && p->next != qi)
+ p = p->next;
+ if (p != NULL)
+ p->next = p->next->next;
+ }
+
+ kfree(qi);
+}
+
+static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
+{
+ uint i;
+ struct brcms_band *band;
+
+ for (i = 0; i < wlc->pub->_nbands; i++) {
+ band = wlc->bandstate[i];
+ if (band->bandtype == BRCM_BAND_5G) {
+ if ((bwcap == BRCMS_N_BW_40ALL)
+ || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
+ band->mimo_cap_40 = true;
+ else
+ band->mimo_cap_40 = false;
+ } else {
+ if (bwcap == BRCMS_N_BW_40ALL)
+ band->mimo_cap_40 = true;
+ else
+ band->mimo_cap_40 = false;
+ }
+ }
+}
static void brcms_c_timers_deinit(struct brcms_c_info *wlc)
{
/* free timer state */
if (wlc->wdtimer) {
- brcms_free_timer(wlc->wl, wlc->wdtimer);
+ brcms_free_timer(wlc->wdtimer);
wlc->wdtimer = NULL;
}
if (wlc->radio_timer) {
- brcms_free_timer(wlc->wl, wlc->radio_timer);
+ brcms_free_timer(wlc->radio_timer);
wlc->radio_timer = NULL;
}
}
@@ -1707,6 +5168,54 @@ static void brcms_c_detach_module(struct brcms_c_info *wlc)
}
/*
+ * low level detach
+ */
+static int brcms_b_detach(struct brcms_c_info *wlc)
+{
+ uint i;
+ struct brcms_hw_band *band;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ int callbacks;
+
+ callbacks = 0;
+
+ if (wlc_hw->sih) {
+ /*
+ * detach interrupt sync mechanism since interrupt is disabled
+ * and per-port interrupt object may has been freed. this must
+ * be done before sb core switch
+ */
+ ai_deregister_intr_callback(wlc_hw->sih);
+ ai_pci_sleep(wlc_hw->sih);
+ }
+
+ brcms_b_detach_dmapio(wlc_hw);
+
+ band = wlc_hw->band;
+ for (i = 0; i < wlc_hw->_nbands; i++) {
+ if (band->pi) {
+ /* Detach this band's phy */
+ wlc_phy_detach(band->pi);
+ band->pi = NULL;
+ }
+ band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
+ }
+
+ /* Free shared phy state */
+ kfree(wlc_hw->phy_sh);
+
+ wlc_phy_shim_detach(wlc_hw->physhim);
+
+ if (wlc_hw->sih) {
+ ai_detach(wlc_hw->sih);
+ wlc_hw->sih = NULL;
+ }
+
+ return callbacks;
+
+}
+
+/*
* Return a count of the number of driver callbacks still pending.
*
* General policy is that brcms_c_detach can only dealloc/free software states.
@@ -1746,268 +5255,130 @@ uint brcms_c_detach(struct brcms_c_info *wlc)
}
/* update state that depends on the current value of "ap" */
-void brcms_c_ap_upd(struct brcms_c_info *wlc)
+static void brcms_c_ap_upd(struct brcms_c_info *wlc)
{
- if (AP_ENAB(wlc->pub))
- /* AP: short not allowed, but not enforced */
- wlc->PLCPHdr_override = BRCMS_PLCP_AUTO;
- else
- /* STA-BSS; short capable */
- wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
+ /* STA-BSS; short capable */
+ wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
/* fixup mpc */
wlc->mpc = true;
}
-/* read hwdisable state and propagate to wlc flag */
-static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
+/* Initialize just the hardware when coming out of POR or S3/S5 system states */
+static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
{
- if (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO || wlc->pub->hw_off)
+ if (wlc_hw->wlc->pub->hw_up)
return;
- if (brcms_b_radio_read_hwdisabled(wlc->hw)) {
- mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
- } else {
- mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
- }
-}
-
-/* return true if Minimum Power Consumption should be entered, false otherwise */
-bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
-{
- return false;
-}
-
-bool brcms_c_ismpc(struct brcms_c_info *wlc)
-{
- return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
-}
-
-void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
-{
- bool mpc_radio, radio_state;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
- * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
- * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
- * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
- * the radio is going down.
+ * Enable pll and xtal, initialize the power control registers,
+ * and force fastclock for the remainder of brcms_c_up().
*/
- if (!wlc->mpc) {
- if (!wlc->pub->radio_disabled)
- return;
- mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
- brcms_c_radio_upd(wlc);
- if (!wlc->pub->radio_disabled)
- brcms_c_radio_monitor_stop(wlc);
- return;
- }
+ brcms_b_xtal(wlc_hw, ON);
+ ai_clkctl_init(wlc_hw->sih);
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+
+ ai_pci_fixcfg(wlc_hw->sih);
/*
- * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in wlc->pub->radio_disabled
- * to go ON, always call radio_upd synchronously
- * to go OFF, postpone radio_upd to later when context is safe(e.g. watchdog)
+ * AI chip doesn't restore bar0win2 on
+ * hibernation/resume, need sw fixup
*/
- radio_state =
- (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
- ON);
- mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
+ if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
+ (wlc_hw->sih->chip == BCM43225_CHIP_ID))
+ wlc_hw->regs = (struct d11regs __iomem *)
+ ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
- if (radio_state == ON && mpc_radio == OFF)
- wlc->mpc_delay_off = wlc->mpc_dlycnt;
- else if (radio_state == OFF && mpc_radio == ON) {
- mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
- brcms_c_radio_upd(wlc);
- if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
- wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
- else
- wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
- wlc->mpc_dur += OSL_SYSUPTIME() - wlc->mpc_laston_ts;
- }
- /* Below logic is meant to capture the transition from mpc off to mpc on for reasons
- * other than wlc->mpc_delay_off keeping the mpc off. In that case reset
- * wlc->mpc_delay_off to wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
+ /*
+ * Inform phy that a POR reset has occurred so
+ * it does a complete phy init
*/
- if ((wlc->prev_non_delay_mpc == false) &&
- (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off) {
- wlc->mpc_delay_off = wlc->mpc_dlycnt;
- }
- wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
-}
-
-/*
- * centralized radio disable/enable function,
- * invoke radio enable/disable after updating hwradio status
- */
-static void brcms_c_radio_upd(struct brcms_c_info *wlc)
-{
- if (wlc->pub->radio_disabled) {
- brcms_c_radio_disable(wlc);
- } else {
- brcms_c_radio_enable(wlc);
- }
-}
+ wlc_phy_por_inform(wlc_hw->band->pi);
-/* maintain LED behavior in down state */
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
-{
- /* maintain LEDs while in down state, turn on sbclk if not available yet */
- /* turn on sbclk if necessary */
- if (!AP_ENAB(wlc->pub)) {
- brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_FLIP);
+ wlc_hw->ucode_loaded = false;
+ wlc_hw->wlc->pub->hw_up = true;
- brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_FLIP);
+ if ((wlc_hw->boardflags & BFL_FEM)
+ && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
+ if (!
+ (wlc_hw->boardrev >= 0x1250
+ && (wlc_hw->boardflags & BFL_FEM_BT)))
+ ai_epa_4313war(wlc_hw->sih);
}
}
-/* update hwradio status and return it */
-bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
-{
- brcms_c_radio_hwdisable_upd(wlc);
-
- return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ? true : false;
-}
-
-void brcms_c_radio_disable(struct brcms_c_info *wlc)
+static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
{
- if (!wlc->pub->up) {
- brcms_c_down_led_upd(wlc);
- return;
- }
-
- brcms_c_radio_monitor_start(wlc);
- brcms_down(wlc->wl);
-}
+ uint coremask;
-static void brcms_c_radio_enable(struct brcms_c_info *wlc)
-{
- if (wlc->pub->up)
- return;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
- if (DEVICEREMOVED(wlc))
- return;
+ /*
+ * Enable pll and xtal, initialize the power control registers,
+ * and force fastclock for the remainder of brcms_c_up().
+ */
+ brcms_b_xtal(wlc_hw, ON);
+ ai_clkctl_init(wlc_hw->sih);
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
- brcms_up(wlc->wl);
-}
+ /*
+ * Configure pci/pcmcia here instead of in brcms_c_attach()
+ * to allow mfg hotswap: down, hotswap (chip power cycle), up.
+ */
+ coremask = (1 << wlc_hw->wlc->core->coreidx);
-/* periodical query hw radio button while driver is "down" */
-static void brcms_c_radio_timer(void *arg)
-{
- struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
+ ai_pci_setup(wlc_hw->sih, coremask);
- if (DEVICEREMOVED(wlc)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
- __func__);
- brcms_down(wlc->wl);
- return;
+ /*
+ * Need to read the hwradio status here to cover the case where the
+ * system is loaded with the hw radio disabled. We do not want to
+ * bring the driver up in this case.
+ */
+ if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
+ /* put SB PCI in down state again */
+ ai_pci_down(wlc_hw->sih);
+ brcms_b_xtal(wlc_hw, OFF);
+ return -ENOMEDIUM;
}
- /* cap mpc off count */
- if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
- wlc->mpc_offcnt++;
-
- brcms_c_radio_hwdisable_upd(wlc);
- brcms_c_radio_upd(wlc);
-}
+ ai_pci_up(wlc_hw->sih);
-static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
-{
- /* Don't start the timer if HWRADIO feature is disabled */
- if (wlc->radio_monitor || (wlc->pub->wlfeatureflag & WL_SWFL_NOHWRADIO))
- return true;
+ /* reset the d11 core */
+ brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
- wlc->radio_monitor = true;
- brcms_c_pllreq(wlc, true, BRCMS_PLLREQ_RADIO_MON);
- brcms_add_timer(wlc->wl, wlc->radio_timer, TIMER_INTERVAL_RADIOCHK,
- true);
- return true;
+ return 0;
}
-bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
+static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
{
- if (!wlc->radio_monitor)
- return true;
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
- wlc->radio_monitor = false;
- brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_RADIO_MON);
- return brcms_del_timer(wlc->wl, wlc->radio_timer);
-}
+ wlc_hw->up = true;
+ wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
-static void brcms_c_watchdog_by_timer(void *arg)
-{
- brcms_c_watchdog(arg);
+ /* FULLY enable dynamic power control and d11 core interrupt */
+ brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+ brcms_intrson(wlc_hw->wlc->wl);
+ return 0;
}
-/* common watchdog code */
-static void brcms_c_watchdog(void *arg)
+/*
+ * Write WME tunable parameters for retransmit/max rate
+ * from wlc struct to ucode
+ */
+static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
{
- struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
- int i;
- struct brcms_bss_cfg *cfg;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
- if (!wlc->pub->up)
- return;
-
- if (DEVICEREMOVED(wlc)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
- __func__);
- brcms_down(wlc->wl);
- return;
- }
-
- /* increment second count */
- wlc->pub->now++;
-
- /* delay radio disable */
- if (wlc->mpc_delay_off) {
- if (--wlc->mpc_delay_off == 0) {
- mboolset(wlc->pub->radio_disabled,
- WL_RADIO_MPC_DISABLE);
- if (wlc->mpc && brcms_c_ismpc(wlc))
- wlc->mpc_offcnt = 0;
- wlc->mpc_laston_ts = OSL_SYSUPTIME();
- }
- }
+ int ac;
- /* mpc sync */
- brcms_c_radio_mpc_upd(wlc);
- /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
- brcms_c_radio_hwdisable_upd(wlc);
- brcms_c_radio_upd(wlc);
- /* if radio is disable, driver may be down, quit here */
- if (wlc->pub->radio_disabled)
+ /* Need clock to do this */
+ if (!wlc->clk)
return;
- brcms_b_watchdog(wlc);
-
- /* occasionally sample mac stat counters to detect 16-bit counter wrap */
- if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)
- brcms_c_statsupd(wlc);
-
- /* Manage TKIP countermeasures timers */
- FOREACH_BSS(wlc, i, cfg) {
- if (cfg->tk_cm_dt) {
- cfg->tk_cm_dt--;
- }
- if (cfg->tk_cm_bt) {
- cfg->tk_cm_bt--;
- }
- }
-
- /* Call any registered watchdog handlers */
- for (i = 0; i < BRCMS_MAXMODULES; i++) {
- if (wlc->modulecb[i].watchdog_fn)
- wlc->modulecb[i].watchdog_fn(wlc->modulecb[i].hdl);
- }
-
- if (BRCMS_ISNPHY(wlc->band) && !wlc->pub->tempsense_disable &&
- ((wlc->pub->now - wlc->tempsense_lasttime) >=
- BRCMS_TEMPSENSE_PERIOD)) {
- wlc->tempsense_lasttime = wlc->pub->now;
- brcms_c_tempsense_upd(wlc);
- }
+ for (ac = 0; ac < AC_COUNT; ac++)
+ brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
+ wlc->wme_retries[ac]);
}
/* make interface operational */
@@ -2016,7 +5387,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
/* HW is turned off so don't try to access it */
- if (wlc->pub->hw_off || DEVICEREMOVED(wlc))
+ if (wlc->pub->hw_off || brcms_deviceremoved(wlc))
return -ENOMEDIUM;
if (!wlc->pub->hw_up) {
@@ -2027,20 +5398,20 @@ int brcms_c_up(struct brcms_c_info *wlc)
if ((wlc->pub->boardflags & BFL_FEM)
&& (wlc->pub->sih->chip == BCM4313_CHIP_ID)) {
if (wlc->pub->boardrev >= 0x1250
- && (wlc->pub->boardflags & BFL_FEM_BT)) {
- brcms_c_mhf(wlc, MHF5, MHF5_4313_GPIOCTRL,
+ && (wlc->pub->boardflags & BFL_FEM_BT))
+ brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL,
MHF5_4313_GPIOCTRL, BRCM_BAND_ALL);
- } else {
- brcms_c_mhf(wlc, MHF4, MHF4_EXTPA_ENABLE,
+ else
+ brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE,
MHF4_EXTPA_ENABLE, BRCM_BAND_ALL);
- }
}
/*
- * Need to read the hwradio status here to cover the case where the system
- * is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
- * if radio is disabled, abort up, lower power, start radio timer and return 0(for NDIS)
- * don't call radio_update to avoid looping brcms_c_up.
+ * Need to read the hwradio status here to cover the case where the
+ * system is loaded with the hw radio disabled. We do not want to bring
+ * the driver up in this case. If radio is disabled, abort up, lower
+ * power, start radio timer and return 0(for NDIS) don't call
+ * radio_update to avoid looping brcms_c_up.
*
* brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only
*/
@@ -2049,20 +5420,15 @@ int brcms_c_up(struct brcms_c_info *wlc)
if (status == -ENOMEDIUM) {
if (!mboolisset
(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) {
- int idx;
- struct brcms_bss_cfg *bsscfg;
+ struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
mboolset(wlc->pub->radio_disabled,
WL_RADIO_HW_DISABLE);
- FOREACH_BSS(wlc, idx, bsscfg) {
- if (!BSSCFG_STA(bsscfg)
- || !bsscfg->enable || !bsscfg->BSS)
- continue;
- wiphy_err(wlc->wiphy, "wl%d.%d: up"
+ if (bsscfg->enable && bsscfg->BSS)
+ wiphy_err(wlc->wiphy, "wl%d: up"
": rfdisable -> "
"bsscfg_disable()\n",
- wlc->pub->unit, idx);
- }
+ wlc->pub->unit);
}
}
}
@@ -2078,15 +5444,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
brcms_c_radio_monitor_stop(wlc);
/* Set EDCF hostflags */
- if (EDCF_ENAB(wlc->pub)) {
- brcms_c_mhf(wlc, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);
- } else {
- brcms_c_mhf(wlc, MHF1, MHF1_EDCF, 0, BRCM_BAND_ALL);
- }
-
- if (BRCMS_WAR16165(wlc))
- brcms_c_mhf(wlc, MHF2, MHF2_PCISLOWCLKWAR, MHF2_PCISLOWCLKWAR,
- BRCM_BAND_ALL);
+ brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);
brcms_init(wlc->wl);
wlc->pub->up = true;
@@ -2100,15 +5458,11 @@ int brcms_c_up(struct brcms_c_info *wlc)
brcms_b_up_finish(wlc->hw);
- /* other software states up after ISR is running */
- /* start APs that were to be brought up but are not up yet */
- /* if (AP_ENAB(wlc->pub)) brcms_c_restart_ap(wlc->ap); */
-
/* Program the TX wme params with the current settings */
brcms_c_wme_retries_write(wlc);
/* start one second watchdog timer */
- brcms_add_timer(wlc->wl, wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true);
+ brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true);
wlc->WDarmed = true;
/* ensure antenna config is up to date */
@@ -2119,29 +5473,80 @@ int brcms_c_up(struct brcms_c_info *wlc)
return 0;
}
-/* Initialize the base precedence map for dequeueing from txq based on WME settings */
-static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
+static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
{
- wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
- memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
+ uint callbacks = 0;
- /* For non-WME, both fifos have overlapping MAXPRIO. So just disable all precedences
- * if either is full.
- */
- if (!EDCF_ENAB(wlc->pub)) {
- wlc->fifo2prec_map[TX_DATA_FIFO] = BRCMS_PREC_BMP_ALL;
- wlc->fifo2prec_map[TX_CTL_FIFO] = BRCMS_PREC_BMP_ALL;
- } else {
- wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
- wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
- wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
- wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
+ return callbacks;
+}
+
+static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
+{
+ bool dev_gone;
+ uint callbacks = 0;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (!wlc_hw->up)
+ return callbacks;
+
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);
+
+ /* disable interrupts */
+ if (dev_gone)
+ wlc_hw->wlc->macintmask = 0;
+ else {
+ /* now disable interrupts */
+ brcms_intrsoff(wlc_hw->wlc->wl);
+
+ /* ensure we're running on the pll clock again */
+ brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
}
+ /* down phy at the last of this stage */
+ callbacks += wlc_phy_down(wlc_hw->band->pi);
+
+ return callbacks;
}
-static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
+static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
{
uint callbacks = 0;
+ bool dev_gone;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+
+ if (!wlc_hw->up)
+ return callbacks;
+
+ wlc_hw->up = false;
+ wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
+
+ dev_gone = brcms_deviceremoved(wlc_hw->wlc);
+
+ if (dev_gone) {
+ wlc_hw->sbclk = false;
+ wlc_hw->clk = false;
+ wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
+
+ /* reclaim any posted packets */
+ brcms_c_flushqueues(wlc_hw->wlc);
+ } else {
+
+ /* Reset and disable the core */
+ if (ai_iscoreup(wlc_hw->sih)) {
+ if (R_REG(&wlc_hw->regs->maccontrol) &
+ MCTL_EN_MAC)
+ brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
+ callbacks += brcms_reset(wlc_hw->wlc->wl);
+ brcms_c_coredisable(wlc_hw);
+ }
+
+ /* turn off primary xtal and pll */
+ if (!wlc_hw->noreset) {
+ ai_pci_down(wlc_hw->sih);
+ brcms_b_xtal(wlc_hw, OFF);
+ }
+ }
return callbacks;
}
@@ -2175,7 +5580,7 @@ uint brcms_c_down(struct brcms_c_info *wlc)
callbacks += brcms_b_bmac_down_prep(wlc->hw);
- dev_gone = DEVICEREMOVED(wlc);
+ dev_gone = brcms_deviceremoved(wlc);
/* Call any registered down handlers */
for (i = 0; i < BRCMS_MAXMODULES; i++) {
@@ -2186,7 +5591,7 @@ uint brcms_c_down(struct brcms_c_info *wlc)
/* cancel the watchdog timer */
if (wlc->WDarmed) {
- if (!brcms_del_timer(wlc->wl, wlc->wdtimer))
+ if (!brcms_del_timer(wlc->wdtimer))
callbacks++;
wlc->WDarmed = false;
}
@@ -2201,9 +5606,8 @@ uint brcms_c_down(struct brcms_c_info *wlc)
brcms_c_txflowcontrol_reset(wlc);
/* flush tx queues */
- for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
+ for (qi = wlc->tx_queues; qi != NULL; qi = qi->next)
brcmu_pktq_flush(&qi->q, true, NULL, NULL);
- }
callbacks += brcms_b_down_finish(wlc->hw);
@@ -2219,30 +5623,31 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
{
int ret = 0;
uint i;
- wlc_rateset_t rs;
+ struct brcms_c_rateset rs;
/* Default to 54g Auto */
/* Advertise and use shortslot (-1/0/1 Auto/Off/On) */
s8 shortslot = BRCMS_SHORTSLOT_AUTO;
- bool shortslot_restrict = false; /* Restrict association to stations that support shortslot
- */
+ bool shortslot_restrict = false; /* Restrict association to stations
+ * that support shortslot
+ */
bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */
/* Advertise and use short preambles (-1/0/1 Auto/Off/On) */
int preamble = BRCMS_PLCP_LONG;
- bool preamble_restrict = false; /* Restrict association to stations that support short
- * preambles
+ bool preamble_restrict = false; /* Restrict association to stations
+ * that support short preambles
*/
struct brcms_band *band;
/* if N-support is enabled, allow Gmode set as long as requested
* Gmode is not GMODE_LEGACY_B
*/
- if (N_ENAB(wlc->pub) && gmode == GMODE_LEGACY_B)
+ if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B)
return -ENOTSUPP;
/* verify that we are dealing with 2G band and grab the band pointer */
if (wlc->band->bandtype == BRCM_BAND_2G)
band = wlc->band;
- else if ((NBANDS(wlc) > 1) &&
+ else if ((wlc->pub->_nbands > 1) &&
(wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G))
band = wlc->bandstate[OTHERBANDUNIT(wlc)];
else
@@ -2257,11 +5662,8 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
if (config == true)
brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);
- /* Clear supported rates filter */
- memset(&wlc->sup_rates_override, 0, sizeof(wlc_rateset_t));
-
/* Clear rateset override */
- memset(&rs, 0, sizeof(wlc_rateset_t));
+ memset(&rs, 0, sizeof(struct brcms_c_rateset));
switch (gmode) {
case GMODE_LEGACY_B:
@@ -2271,9 +5673,6 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
break;
case GMODE_LRS:
- if (AP_ENAB(wlc->pub))
- brcms_c_rateset_copy(&cck_rates,
- &wlc->sup_rates_override);
break;
case GMODE_AUTO:
@@ -2287,10 +5686,6 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
break;
case GMODE_PERFORMANCE:
- if (AP_ENAB(wlc->pub)) /* Put all rates into the Supported Rates element */
- brcms_c_rateset_copy(&cck_ofdm_rates,
- &wlc->sup_rates_override);
-
shortslot = BRCMS_SHORTSLOT_ON;
shortslot_restrict = true;
ofdm_basic = true;
@@ -2305,46 +5700,10 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
return -ENOTSUPP;
}
- /*
- * If we are switching to gmode == GMODE_LEGACY_B,
- * clean up rate info that may refer to OFDM rates.
- */
- if ((gmode == GMODE_LEGACY_B) && (band->gmode != GMODE_LEGACY_B)) {
- band->gmode = gmode;
- if (band->rspec_override && !IS_CCK(band->rspec_override)) {
- band->rspec_override = 0;
- brcms_c_reprate_init(wlc);
- }
- if (band->mrspec_override && !IS_CCK(band->mrspec_override)) {
- band->mrspec_override = 0;
- }
- }
-
band->gmode = gmode;
wlc->shortslot_override = shortslot;
- if (AP_ENAB(wlc->pub)) {
- /* wlc->ap->shortslot_restrict = shortslot_restrict; */
- wlc->PLCPHdr_override =
- (preamble !=
- BRCMS_PLCP_LONG) ? BRCMS_PLCP_SHORT : BRCMS_PLCP_AUTO;
- }
-
- if ((AP_ENAB(wlc->pub) && preamble != BRCMS_PLCP_LONG)
- || preamble == BRCMS_PLCP_SHORT)
- wlc->default_bss->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
- else
- wlc->default_bss->capability &= ~WLAN_CAPABILITY_SHORT_PREAMBLE;
-
- /* Update shortslot capability bit for AP and IBSS */
- if ((AP_ENAB(wlc->pub) && shortslot == BRCMS_SHORTSLOT_AUTO) ||
- shortslot == BRCMS_SHORTSLOT_ON)
- wlc->default_bss->capability |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
- else
- wlc->default_bss->capability &=
- ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
-
/* Use the default 11g rateset */
if (!rs.count)
brcms_c_rateset_copy(&cck_ofdm_rates, &rs);
@@ -2366,92 +5725,41 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
return ret;
}
-static int brcms_c_nmode_validate(struct brcms_c_info *wlc, s32 nmode)
-{
- int err = 0;
-
- switch (nmode) {
-
- case OFF:
- break;
-
- case AUTO:
- case WL_11N_2x2:
- case WL_11N_3x3:
- if (!(BRCMS_PHY_11N_CAP(wlc->band)))
- err = -EINVAL;
- break;
-
- default:
- err = -EINVAL;
- break;
- }
-
- return err;
-}
-
-int brcms_c_set_nmode(struct brcms_c_info *wlc, s32 nmode)
+int brcms_c_set_nmode(struct brcms_c_info *wlc)
{
uint i;
- int err;
+ s32 nmode = AUTO;
- err = brcms_c_nmode_validate(wlc, nmode);
- if (err)
- return err;
-
- switch (nmode) {
- case OFF:
- wlc->pub->_n_enab = OFF;
- wlc->default_bss->flags &= ~BRCMS_BSS_HT;
- /* delete the mcs rates from the default and hw ratesets */
- brcms_c_rateset_mcs_clear(&wlc->default_bss->rateset);
- for (i = 0; i < NBANDS(wlc); i++) {
- memset(wlc->bandstate[i]->hw_rateset.mcs, 0,
- MCSSET_LEN);
- if (IS_MCS(wlc->band->rspec_override)) {
- wlc->bandstate[i]->rspec_override = 0;
- brcms_c_reprate_init(wlc);
- }
- if (IS_MCS(wlc->band->mrspec_override))
- wlc->bandstate[i]->mrspec_override = 0;
- }
- break;
-
- case AUTO:
- if (wlc->stf->txstreams == WL_11N_3x3)
- nmode = WL_11N_3x3;
- else
- nmode = WL_11N_2x2;
- case WL_11N_2x2:
- case WL_11N_3x3:
- /* force GMODE_AUTO if NMODE is ON */
- brcms_c_set_gmode(wlc, GMODE_AUTO, true);
- if (nmode == WL_11N_3x3)
- wlc->pub->_n_enab = SUPPORT_HT;
- else
- wlc->pub->_n_enab = SUPPORT_11N;
- wlc->default_bss->flags |= BRCMS_BSS_HT;
- /* add the mcs rates to the default and hw ratesets */
- brcms_c_rateset_mcs_build(&wlc->default_bss->rateset,
- wlc->stf->txstreams);
- for (i = 0; i < NBANDS(wlc); i++)
- memcpy(wlc->bandstate[i]->hw_rateset.mcs,
- wlc->default_bss->rateset.mcs, MCSSET_LEN);
- break;
+ if (wlc->stf->txstreams == WL_11N_3x3)
+ nmode = WL_11N_3x3;
+ else
+ nmode = WL_11N_2x2;
- default:
- break;
- }
+ /* force GMODE_AUTO if NMODE is ON */
+ brcms_c_set_gmode(wlc, GMODE_AUTO, true);
+ if (nmode == WL_11N_3x3)
+ wlc->pub->_n_enab = SUPPORT_HT;
+ else
+ wlc->pub->_n_enab = SUPPORT_11N;
+ wlc->default_bss->flags |= BRCMS_BSS_HT;
+ /* add the mcs rates to the default and hw ratesets */
+ brcms_c_rateset_mcs_build(&wlc->default_bss->rateset,
+ wlc->stf->txstreams);
+ for (i = 0; i < wlc->pub->_nbands; i++)
+ memcpy(wlc->bandstate[i]->hw_rateset.mcs,
+ wlc->default_bss->rateset.mcs, MCSSET_LEN);
- return err;
+ return 0;
}
-static int brcms_c_set_rateset(struct brcms_c_info *wlc, wlc_rateset_t *rs_arg)
+static int
+brcms_c_set_internal_rateset(struct brcms_c_info *wlc,
+ struct brcms_c_rateset *rs_arg)
{
- wlc_rateset_t rs, new;
+ struct brcms_c_rateset rs, new;
uint bandunit;
- memcpy(&rs, rs_arg, sizeof(wlc_rateset_t));
+ memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset));
/* check for bad count value */
if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES))
@@ -2459,16 +5767,16 @@ static int brcms_c_set_rateset(struct brcms_c_info *wlc, wlc_rateset_t *rs_arg)
/* try the current band */
bandunit = wlc->band->bandunit;
- memcpy(&new, &rs, sizeof(wlc_rateset_t));
+ memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
if (brcms_c_rate_hwrs_filter_sort_validate
(&new, &wlc->bandstate[bandunit]->hw_rateset, true,
wlc->stf->txstreams))
goto good;
/* try the other band */
- if (IS_MBAND_UNLOCKED(wlc)) {
+ if (brcms_is_mband_unlocked(wlc)) {
bandunit = OTHERBANDUNIT(wlc);
- memcpy(&new, &rs, sizeof(wlc_rateset_t));
+ memcpy(&new, &rs, sizeof(struct brcms_c_rateset));
if (brcms_c_rate_hwrs_filter_sort_validate(&new,
&wlc->
bandstate[bandunit]->
@@ -2481,299 +5789,176 @@ static int brcms_c_set_rateset(struct brcms_c_info *wlc, wlc_rateset_t *rs_arg)
good:
/* apply new rateset */
- memcpy(&wlc->default_bss->rateset, &new, sizeof(wlc_rateset_t));
+ memcpy(&wlc->default_bss->rateset, &new,
+ sizeof(struct brcms_c_rateset));
memcpy(&wlc->bandstate[bandunit]->defrateset, &new,
- sizeof(wlc_rateset_t));
+ sizeof(struct brcms_c_rateset));
return 0;
}
-/* simplified integer set interface for common ioctl handler */
-int brcms_c_set(struct brcms_c_info *wlc, int cmd, int arg)
-{
- return brcms_c_ioctl(wlc, cmd, (void *)&arg, sizeof(arg), NULL);
-}
-
-/* simplified integer get interface for common ioctl handler */
-int brcms_c_get(struct brcms_c_info *wlc, int cmd, int *arg)
-{
- return brcms_c_ioctl(wlc, cmd, arg, sizeof(int), NULL);
-}
-
static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)
{
u8 r;
bool war = false;
- if (wlc->cfg->associated)
- r = wlc->cfg->current_bss->rateset.rates[0];
+ if (wlc->bsscfg->associated)
+ r = wlc->bsscfg->current_bss->rateset.rates[0];
else
r = wlc->default_bss->rateset.rates[0];
wlc_phy_ofdm_rateset_war(wlc->band->pi, war);
-
- return;
}
-int
-brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
- struct brcms_c_if *wlcif)
+int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)
{
- return _brcms_c_ioctl(wlc, cmd, arg, len, wlcif);
-}
-
-/* common ioctl handler. return: 0=ok, -1=error, positive=particular error */
-static int
-_brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
- struct brcms_c_if *wlcif)
-{
- int val, *pval;
- bool bool_val;
- int bcmerror;
- struct scb *nextscb;
- bool ta_ok;
- uint band;
- struct brcms_bss_cfg *bsscfg;
- struct brcms_bss_info *current_bss;
-
- /* update bsscfg pointer */
- bsscfg = wlc->cfg;
- current_bss = bsscfg->current_bss;
-
- /* initialize the following to get rid of compiler warning */
- nextscb = NULL;
- ta_ok = false;
- band = 0;
-
- /* If the device is turned off, then it's not "removed" */
- if (!wlc->pub->hw_off && DEVICEREMOVED(wlc)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
- __func__);
- brcms_down(wlc->wl);
- return -EBADE;
- }
+ u16 chspec = ch20mhz_chspec(channel);
- /* default argument is generic integer */
- pval = arg ? (int *)arg : NULL;
+ if (channel < 0 || channel > MAXCHANNEL)
+ return -EINVAL;
- /* This will prevent the misaligned access */
- if (pval && (u32) len >= sizeof(val))
- memcpy(&val, pval, sizeof(val));
- else
- val = 0;
+ if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))
+ return -EINVAL;
- /* bool conversion to avoid duplication below */
- bool_val = val != 0;
- bcmerror = 0;
- if ((arg == NULL) || (len <= 0)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Command %d needs arguments\n",
- wlc->pub->unit, __func__, cmd);
- bcmerror = -EINVAL;
- goto done;
+ if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {
+ if (wlc->band->bandunit != chspec_bandunit(chspec))
+ wlc->bandinit_pending = true;
+ else
+ wlc->bandinit_pending = false;
}
- switch (cmd) {
-
- case BRCM_SET_CHANNEL:{
- chanspec_t chspec = CH20MHZ_CHSPEC(val);
-
- if (val < 0 || val > MAXCHANNEL) {
- bcmerror = -EINVAL;
- break;
- }
-
- if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec)) {
- bcmerror = -EINVAL;
- break;
- }
-
- if (!wlc->pub->up && IS_MBAND_UNLOCKED(wlc)) {
- if (wlc->band->bandunit !=
- CHSPEC_BANDUNIT(chspec))
- wlc->bandinit_pending = true;
- else
- wlc->bandinit_pending = false;
- }
-
- wlc->default_bss->chanspec = chspec;
- /* brcms_c_BSSinit() will sanitize the rateset before
- * using it.. */
- if (wlc->pub->up &&
- (BRCMS_BAND_PI_RADIO_CHANSPEC != chspec)) {
- brcms_c_set_home_chanspec(wlc, chspec);
- brcms_c_suspend_mac_and_wait(wlc);
- brcms_c_set_chanspec(wlc, chspec);
- brcms_c_enable_mac(wlc);
- }
- break;
- }
-
- case BRCM_SET_SRL:
- if (val >= 1 && val <= RETRY_SHORT_MAX) {
- int ac;
- wlc->SRL = (u16) val;
-
- brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
-
- for (ac = 0; ac < AC_COUNT; ac++) {
- BRCMS_WME_RETRY_SHORT_SET(wlc, ac, wlc->SRL);
- }
- brcms_c_wme_retries_write(wlc);
- } else
- bcmerror = -EINVAL;
- break;
-
- case BRCM_SET_LRL:
- if (val >= 1 && val <= 255) {
- int ac;
- wlc->LRL = (u16) val;
+ wlc->default_bss->chanspec = chspec;
+ /* brcms_c_BSSinit() will sanitize the rateset before
+ * using it.. */
+ if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {
+ brcms_c_set_home_chanspec(wlc, chspec);
+ brcms_c_suspend_mac_and_wait(wlc);
+ brcms_c_set_chanspec(wlc, chspec);
+ brcms_c_enable_mac(wlc);
+ }
+ return 0;
+}
- brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
+int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
+{
+ int ac;
- for (ac = 0; ac < AC_COUNT; ac++) {
- BRCMS_WME_RETRY_LONG_SET(wlc, ac, wlc->LRL);
- }
- brcms_c_wme_retries_write(wlc);
- } else
- bcmerror = -EINVAL;
- break;
+ if (srl < 1 || srl > RETRY_SHORT_MAX ||
+ lrl < 1 || lrl > RETRY_SHORT_MAX)
+ return -EINVAL;
- case BRCM_GET_CURR_RATESET:{
- wl_rateset_t *ret_rs = (wl_rateset_t *) arg;
- wlc_rateset_t *rs;
+ wlc->SRL = srl;
+ wlc->LRL = lrl;
- if (wlc->pub->associated)
- rs = &current_bss->rateset;
- else
- rs = &wlc->default_bss->rateset;
+ brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
- if (len < (int)(rs->count + sizeof(rs->count))) {
- bcmerror = -EOVERFLOW;
- break;
- }
+ for (ac = 0; ac < AC_COUNT; ac++) {
+ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
+ EDCF_SHORT, wlc->SRL);
+ wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],
+ EDCF_LONG, wlc->LRL);
+ }
+ brcms_c_wme_retries_write(wlc);
- /* Copy only legacy rateset section */
- ret_rs->count = rs->count;
- memcpy(&ret_rs->rates, &rs->rates, rs->count);
- break;
- }
+ return 0;
+}
- case BRCM_SET_RATESET:{
- wlc_rateset_t rs;
- wl_rateset_t *in_rs = (wl_rateset_t *) arg;
+void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *currs)
+{
+ struct brcms_c_rateset *rs;
- if (len < (int)(in_rs->count + sizeof(in_rs->count))) {
- bcmerror = -EOVERFLOW;
- break;
- }
+ if (wlc->pub->associated)
+ rs = &wlc->bsscfg->current_bss->rateset;
+ else
+ rs = &wlc->default_bss->rateset;
- if (in_rs->count > BRCMS_NUMRATES) {
- bcmerror = -ENOBUFS;
- break;
- }
+ /* Copy only legacy rateset section */
+ currs->count = rs->count;
+ memcpy(&currs->rates, &rs->rates, rs->count);
+}
- memset(&rs, 0, sizeof(wlc_rateset_t));
-
- /* Copy only legacy rateset section */
- rs.count = in_rs->count;
- memcpy(&rs.rates, &in_rs->rates, rs.count);
-
- /* merge rateset coming in with the current mcsset */
- if (N_ENAB(wlc->pub)) {
- if (bsscfg->associated)
- memcpy(rs.mcs,
- &current_bss->rateset.mcs[0],
- MCSSET_LEN);
- else
- memcpy(rs.mcs,
- &wlc->default_bss->rateset.mcs[0],
- MCSSET_LEN);
- }
+int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)
+{
+ struct brcms_c_rateset internal_rs;
+ int bcmerror;
- bcmerror = brcms_c_set_rateset(wlc, &rs);
+ if (rs->count > BRCMS_NUMRATES)
+ return -ENOBUFS;
- if (!bcmerror)
- brcms_c_ofdm_rateset_war(wlc);
+ memset(&internal_rs, 0, sizeof(struct brcms_c_rateset));
- break;
- }
+ /* Copy only legacy rateset section */
+ internal_rs.count = rs->count;
+ memcpy(&internal_rs.rates, &rs->rates, internal_rs.count);
- case BRCM_SET_BCNPRD:
- /* range [1, 0xffff] */
- if (val >= DOT11_MIN_BEACON_PERIOD
- && val <= DOT11_MAX_BEACON_PERIOD)
- wlc->default_bss->beacon_period = (u16) val;
+ /* merge rateset coming in with the current mcsset */
+ if (wlc->pub->_n_enab & SUPPORT_11N) {
+ struct brcms_bss_info *mcsset_bss;
+ if (wlc->bsscfg->associated)
+ mcsset_bss = wlc->bsscfg->current_bss;
else
- bcmerror = -EINVAL;
- break;
+ mcsset_bss = wlc->default_bss;
+ memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0],
+ MCSSET_LEN);
+ }
- case BRCM_GET_PHYLIST:
- {
- unsigned char *cp = arg;
- if (len < 3) {
- bcmerror = -EOVERFLOW;
- break;
- }
+ bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs);
+ if (!bcmerror)
+ brcms_c_ofdm_rateset_war(wlc);
- if (BRCMS_ISNPHY(wlc->band))
- *cp++ = 'n';
- else if (BRCMS_ISLCNPHY(wlc->band))
- *cp++ = 'c';
- else if (BRCMS_ISSSLPNPHY(wlc->band))
- *cp++ = 's';
- *cp = '\0';
- break;
- }
+ return bcmerror;
+}
- case BRCMS_SET_SHORTSLOT_OVERRIDE:
- if (val != BRCMS_SHORTSLOT_AUTO && val != BRCMS_SHORTSLOT_OFF &&
- val != BRCMS_SHORTSLOT_ON) {
- bcmerror = -EINVAL;
- break;
- }
+int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)
+{
+ if (period < DOT11_MIN_BEACON_PERIOD ||
+ period > DOT11_MAX_BEACON_PERIOD)
+ return -EINVAL;
- wlc->shortslot_override = (s8) val;
+ wlc->default_bss->beacon_period = period;
+ return 0;
+}
- /* shortslot is an 11g feature, so no more work if we are
- * currently on the 5G band
- */
- if (BAND_5G(wlc->band->bandtype))
- break;
+u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)
+{
+ return wlc->band->phytype;
+}
- if (wlc->pub->up && wlc->pub->associated) {
- /* let watchdog or beacon processing update shortslot */
- } else if (wlc->pub->up) {
- /* unassociated shortslot is off */
- brcms_c_switch_shortslot(wlc, false);
- } else {
- /* driver is down, so just update the brcms_c_info
- * value */
- if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO) {
- wlc->shortslot = false;
- } else {
- wlc->shortslot =
- (wlc->shortslot_override ==
- BRCMS_SHORTSLOT_ON);
- }
- }
+void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)
+{
+ wlc->shortslot_override = sslot_override;
- break;
+ /*
+ * shortslot is an 11g feature, so no more work if we are
+ * currently on the 5G band
+ */
+ if (wlc->band->bandtype == BRCM_BAND_5G)
+ return;
+ if (wlc->pub->up && wlc->pub->associated) {
+ /* let watchdog or beacon processing update shortslot */
+ } else if (wlc->pub->up) {
+ /* unassociated shortslot is off */
+ brcms_c_switch_shortslot(wlc, false);
+ } else {
+ /* driver is down, so just update the brcms_c_info
+ * value */
+ if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)
+ wlc->shortslot = false;
+ else
+ wlc->shortslot =
+ (wlc->shortslot_override ==
+ BRCMS_SHORTSLOT_ON);
}
- done:
-
- if (bcmerror)
- wlc->pub->bcmerror = bcmerror;
-
- return bcmerror;
}
/*
* register watchdog and down handlers.
*/
int brcms_c_module_register(struct brcms_pub *pub,
- const char *name, void *hdl,
- watchdog_fn_t w_fn, down_fn_t d_fn)
+ const char *name, struct brcms_info *hdl,
+ int (*d_fn)(void *handle))
{
struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
int i;
@@ -2784,7 +5969,6 @@ int brcms_c_module_register(struct brcms_pub *pub,
strncpy(wlc->modulecb[i].name, name,
sizeof(wlc->modulecb[i].name) - 1);
wlc->modulecb[i].hdl = hdl;
- wlc->modulecb[i].watchdog_fn = w_fn;
wlc->modulecb[i].down_fn = d_fn;
return 0;
}
@@ -2794,8 +5978,8 @@ int brcms_c_module_register(struct brcms_pub *pub,
}
/* unregister module callbacks */
-int
-brcms_c_module_unregister(struct brcms_pub *pub, const char *name, void *hdl)
+int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
+ struct brcms_info *hdl)
{
struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;
int i;
@@ -2815,21 +5999,6 @@ brcms_c_module_unregister(struct brcms_pub *pub, const char *name, void *hdl)
return -ENODATA;
}
-/* Write WME tunable parameters for retransmit/max rate from wlc struct to ucode */
-static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
-{
- int ac;
-
- /* Need clock to do this */
- if (!wlc->clk)
- return;
-
- for (ac = 0; ac < AC_COUNT; ac++) {
- brcms_c_write_shm(wlc, M_AC_TXLMT_ADDR(ac),
- wlc->wme_retries[ac]);
- }
-}
-
#ifdef BCMDBG
static const char * const supr_reason[] = {
"None", "PMQ Entry", "Flush request",
@@ -2882,59 +6051,6 @@ void brcms_c_print_txstatus(struct tx_status *txs)
#endif /* defined(BCMDBG) */
}
-void brcms_c_statsupd(struct brcms_c_info *wlc)
-{
- int i;
- struct macstat macstats;
-#ifdef BCMDBG
- u16 delta;
- u16 rxf0ovfl;
- u16 txfunfl[NFIFO];
-#endif /* BCMDBG */
-
- /* if driver down, make no sense to update stats */
- if (!wlc->pub->up)
- return;
-
-#ifdef BCMDBG
- /* save last rx fifo 0 overflow count */
- rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl;
-
- /* save last tx fifo underflow count */
- for (i = 0; i < NFIFO; i++)
- txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i];
-#endif /* BCMDBG */
-
- /* Read mac stats from contiguous shared memory */
- brcms_b_copyfrom_shm(wlc->hw, M_UCODE_MACSTAT,
- &macstats, sizeof(struct macstat));
-
-#ifdef BCMDBG
- /* check for rx fifo 0 overflow */
- delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
- if (delta)
- wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
- wlc->pub->unit, delta);
-
- /* check for tx fifo underflows */
- for (i = 0; i < NFIFO; i++) {
- delta =
- (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
- txfunfl[i]);
- if (delta)
- wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
- "\n", wlc->pub->unit, delta, i);
- }
-#endif /* BCMDBG */
-
- /* merge counters from dma module */
- for (i = 0; i < NFIFO; i++) {
- if (wlc->hw->di[i]) {
- dma_counterreset(wlc->hw->di[i]);
- }
- }
-}
-
bool brcms_c_chipmatch(u16 vendor, u16 device)
{
if (vendor != PCI_VENDOR_ID_BROADCOM) {
@@ -3042,6 +6158,62 @@ void brcms_c_print_txdesc(struct d11txh *txh)
#endif /* defined(BCMDBG) */
#if defined(BCMDBG)
+int
+brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
+ int len)
+{
+ int i;
+ char *p = buf;
+ char hexstr[16];
+ int slen = 0, nlen = 0;
+ u32 bit;
+ const char *name;
+
+ if (len < 2 || !buf)
+ return 0;
+
+ buf[0] = '\0';
+
+ for (i = 0; flags != 0; i++) {
+ bit = bd[i].bit;
+ name = bd[i].name;
+ if (bit == 0 && flags != 0) {
+ /* print any unnamed bits */
+ snprintf(hexstr, 16, "0x%X", flags);
+ name = hexstr;
+ flags = 0; /* exit loop */
+ } else if ((flags & bit) == 0)
+ continue;
+ flags &= ~bit;
+ nlen = strlen(name);
+ slen += nlen;
+ /* count btwn flag space */
+ if (flags != 0)
+ slen += 1;
+ /* need NULL char as well */
+ if (len <= slen)
+ break;
+ /* copy NULL char but don't count it */
+ strncpy(p, name, nlen + 1);
+ p += nlen;
+ /* copy btwn flag space and NULL char */
+ if (flags != 0)
+ p += snprintf(p, 2, " ");
+ len -= slen;
+ }
+
+ /* indicate the str was too short */
+ if (flags != 0) {
+ if (len < 2)
+ p -= 2 - len; /* overwrite last char */
+ p += snprintf(p, 2, ">");
+ }
+
+ return (int)(p - buf);
+}
+#endif /* defined(BCMDBG) */
+
+#if defined(BCMDBG)
void brcms_c_print_rxh(struct d11rxhdr *rxh)
{
u16 len = rxh->RxFrameSize;
@@ -3053,7 +6225,7 @@ void brcms_c_print_rxh(struct d11rxhdr *rxh)
u16 macstatus2 = rxh->RxStatus2;
char flagstr[64];
char lenbuf[20];
- static const struct brcmu_bit_desc macstat_flags[] = {
+ static const struct brcms_c_bit_desc macstat_flags[] = {
{RXS_FCSERR, "FCSErr"},
{RXS_RESPFRAMETX, "Reply"},
{RXS_PBPRES, "PADDING"},
@@ -3067,7 +6239,7 @@ void brcms_c_print_rxh(struct d11rxhdr *rxh)
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, rxh,
sizeof(struct d11rxhdr));
- brcmu_format_flags(macstat_flags, macstatus1, flagstr, 64);
+ brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64);
snprintf(lenbuf, sizeof(lenbuf), "0x%x", len);
@@ -3082,29 +6254,30 @@ void brcms_c_print_rxh(struct d11rxhdr *rxh)
}
#endif /* defined(BCMDBG) */
-static u16 brcms_c_rate_shm_offset(struct brcms_c_info *wlc, u8 rate)
+u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
{
- return brcms_b_rate_shm_offset(wlc->hw, rate);
-}
+ u16 table_ptr;
+ u8 phy_rate, index;
-/* Callback for device removed */
+ /* get the phy specific rate encoding for the PLCP SIGNAL field */
+ if (is_ofdm_rate(rate))
+ table_ptr = M_RT_DIRMAP_A;
+ else
+ table_ptr = M_RT_DIRMAP_B;
-/*
- * Attempts to queue a packet onto a multiple-precedence queue,
- * if necessary evicting a lower precedence packet from the queue.
- *
- * 'prec' is the precedence number that has already been mapped
- * from the packet priority.
- *
- * Returns true if packet consumed (queued), false if not.
- */
-bool
-brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q, void *pkt, int prec)
-{
- return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
+ /* for a given rate, the LS-nibble of the PLCP SIGNAL field is
+ * the index into the rate table.
+ */
+ phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
+ index = phy_rate & 0xf;
+
+ /* Find the SHM pointer to the rate table entry by looking in the
+ * Direct-map Table
+ */
+ return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
}
-bool
+static bool
brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
struct sk_buff *pkt, int prec, bool head)
{
@@ -3127,7 +6300,7 @@ brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
if (eprec >= 0) {
bool discard_oldest;
- discard_oldest = AC_BITMAP_TST(wlc->wme_dp, eprec);
+ discard_oldest = ac_bitmap_tst(0, eprec);
/* Refuse newer packet unless configured to discard oldest */
if (eprec == prec && !discard_oldest) {
@@ -3151,10 +6324,24 @@ brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
return true;
}
-void brcms_c_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu,
- uint prec)
+/*
+ * Attempts to queue a packet onto a multiple-precedence queue,
+ * if necessary evicting a lower precedence packet from the queue.
+ *
+ * 'prec' is the precedence number that has already been mapped
+ * from the packet priority.
+ *
+ * Returns true if packet consumed (queued), false if not.
+ */
+static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
+ struct sk_buff *pkt, int prec)
+{
+ return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
+}
+
+void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
+ struct sk_buff *sdu, uint prec)
{
- struct brcms_c_info *wlc = (struct brcms_c_info *) ctx;
struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */
struct pktq *q = &qi->q;
int prio;
@@ -3162,124 +6349,12 @@ void brcms_c_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu,
prio = sdu->priority;
if (!brcms_c_prec_enq(wlc, q, sdu, prec)) {
- if (!EDCF_ENAB(wlc->pub)
- || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL))
- wiphy_err(wlc->wiphy, "wl%d: txq_enq: txq overflow"
- "\n", wlc->pub->unit);
-
/*
* we might hit this condtion in case
* packet flooding from mac80211 stack
*/
brcmu_pkt_buf_free_skb(sdu);
}
-
- /* Check if flow control needs to be turned on after enqueuing the packet
- * Don't turn on flow control if EDCF is enabled. Driver would make the decision on what
- * to drop instead of relying on stack to make the right decision
- */
- if (!EDCF_ENAB(wlc->pub)
- || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) {
- if (pktq_len(q) >= wlc->pub->tunables->datahiwat) {
- brcms_c_txflowcontrol(wlc, qi, ON, ALLPRIO);
- }
- } else if (wlc->pub->_priofc) {
- if (pktq_plen(q, wlc_prio2prec_map[prio]) >=
- wlc->pub->tunables->datahiwat) {
- brcms_c_txflowcontrol(wlc, qi, ON, prio);
- }
- }
-}
-
-bool
-brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
- struct ieee80211_hw *hw)
-{
- u8 prio;
- uint fifo;
- void *pkt;
- struct scb *scb = &global_scb;
- struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
-
- /* 802.11 standard requires management traffic to go at highest priority */
- prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
- MAXPRIO;
- fifo = prio2fifo[prio];
- pkt = sdu;
- if (unlikely
- (brcms_c_d11hdrs_mac80211(
- wlc, hw, pkt, scb, 0, 1, fifo, 0, NULL, 0)))
- return -EINVAL;
- brcms_c_txq_enq(wlc, scb, pkt, BRCMS_PRIO_TO_PREC(prio));
- brcms_c_send_q(wlc);
- return 0;
-}
-
-void brcms_c_send_q(struct brcms_c_info *wlc)
-{
- struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
- int prec;
- u16 prec_map;
- int err = 0, i, count;
- uint fifo;
- struct brcms_txq_info *qi = wlc->pkt_queue;
- struct pktq *q = &qi->q;
- struct ieee80211_tx_info *tx_info;
-
- if (in_send_q)
- return;
- else
- in_send_q = true;
-
- prec_map = wlc->tx_prec_map;
-
- /* Send all the enq'd pkts that we can.
- * Dequeue packets with precedence with empty HW fifo only
- */
- while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
- tx_info = IEEE80211_SKB_CB(pkt[0]);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
- err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
- } else {
- count = 1;
- err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
- if (!err) {
- for (i = 0; i < count; i++) {
- brcms_c_txfifo(wlc, fifo, pkt[i], true,
- 1);
- }
- }
- }
-
- if (err == -EBUSY) {
- brcmu_pktq_penq_head(q, prec, pkt[0]);
- /* If send failed due to any other reason than a change in
- * HW FIFO condition, quit. Otherwise, read the new prec_map!
- */
- if (prec_map == wlc->tx_prec_map)
- break;
- prec_map = wlc->tx_prec_map;
- }
- }
-
- /* Check if flow control needs to be turned off after sending the packet */
- if (!EDCF_ENAB(wlc->pub)
- || (wlc->pub->wlfeatureflag & WL_SWFL_FLOWCONTROL)) {
- if (brcms_c_txflowcontrol_prio_isset(wlc, qi, ALLPRIO)
- && (pktq_len(q) < wlc->pub->tunables->datahiwat / 2)) {
- brcms_c_txflowcontrol(wlc, qi, OFF, ALLPRIO);
- }
- } else if (wlc->pub->_priofc) {
- int prio;
- for (prio = MAXPRIO; prio >= 0; prio--) {
- if (brcms_c_txflowcontrol_prio_isset(wlc, qi, prio) &&
- (pktq_plen(q, wlc_prio2prec_map[prio]) <
- wlc->pub->tunables->datahiwat / 2)) {
- brcms_c_txflowcontrol(wlc, qi, OFF, prio);
- }
- }
- }
- in_send_q = false;
}
/*
@@ -3303,92 +6378,284 @@ bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg,
return frameid;
}
-void
-brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
- bool commit, s8 txpktpend)
+static uint
+brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
+ u8 preamble_type)
{
- u16 frameid = INVALIDFID;
- struct d11txh *txh;
-
- txh = (struct d11txh *) (p->data);
+ uint dur = 0;
- /* When a BC/MC frame is being committed to the BCMC fifo via DMA (NOT PIO), update
- * ucode or BSS info as appropriate.
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
+ /*
+ * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
+ * is less than or equal to the rate of the immediately previous
+ * frame in the FES
*/
- if (fifo == TX_BCMC_FIFO) {
- frameid = le16_to_cpu(txh->TxFrameID);
+ rspec = brcms_basic_rate(wlc, rspec);
+ /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
+ dur =
+ brcms_c_calc_frame_time(wlc, rspec, preamble_type,
+ (DOT11_ACK_LEN + FCS_LEN));
+ return dur;
+}
- }
+static uint
+brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
+ u8 preamble_type)
+{
+ BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
+ wlc->pub->unit, rspec, preamble_type);
+ return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
+}
- if (BRCMS_WAR16165(wlc))
- brcms_c_war16165(wlc, true);
+static uint
+brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
+ u8 preamble_type)
+{
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
+ "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
+ /*
+ * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
+ * is less than or equal to the rate of the immediately previous
+ * frame in the FES
+ */
+ rspec = brcms_basic_rate(wlc, rspec);
+ /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
+ return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
+ (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
+ FCS_LEN));
+}
+/* brcms_c_compute_frame_dur()
+ *
+ * Calculate the 802.11 MAC header DUR field for MPDU
+ * DUR for a single frame = 1 SIFS + 1 ACK
+ * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
+ *
+ * rate MPDU rate in unit of 500kbps
+ * next_frag_len next MPDU length in bytes
+ * preamble_type use short/GF or long/MM PLCP header
+ */
+static u16
+brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,
+ u8 preamble_type, uint next_frag_len)
+{
+ u16 dur, sifs;
- /* Bump up pending count for if not using rpc. If rpc is used, this will be handled
- * in brcms_b_txfifo()
- */
- if (commit) {
- TXPKTPENDINC(wlc, fifo, txpktpend);
- BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
- txpktpend, TXPKTPENDGET(wlc, fifo));
- }
+ sifs = get_sifs(wlc->band);
- /* Commit BCMC sequence number in the SHM frame ID location */
- if (frameid != INVALIDFID)
- BCMCFID(wlc, frameid);
+ dur = sifs;
+ dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
- if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) {
- wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
+ if (next_frag_len) {
+ /* Double the current DUR to get 2 SIFS + 2 ACKs */
+ dur *= 2;
+ /* add another SIFS and the frag time */
+ dur += sifs;
+ dur +=
+ (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
+ next_frag_len);
}
+ return dur;
}
-void
-brcms_c_compute_plcp(struct brcms_c_info *wlc, ratespec_t rspec,
- uint length, u8 *plcp)
+/* The opposite of brcms_c_calc_frame_time */
+static uint
+brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
+ u8 preamble_type, uint dur)
{
- if (IS_MCS(rspec)) {
- brcms_c_compute_mimo_plcp(rspec, length, plcp);
- } else if (IS_OFDM(rspec)) {
- brcms_c_compute_ofdm_plcp(rspec, length, plcp);
+ uint nsyms, mac_len, Ndps, kNdps;
+ uint rate = rspec2rate(ratespec);
+
+ BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
+ wlc->pub->unit, ratespec, preamble_type, dur);
+
+ if (is_mcs_rate(ratespec)) {
+ uint mcs = ratespec & RSPEC_RATE_MASK;
+ int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
+ dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
+ /* payload calculation matches that of regular ofdm */
+ if (wlc->band->bandtype == BRCM_BAND_2G)
+ dur -= DOT11_OFDM_SIGNAL_EXTENSION;
+ /* kNdbps = kbps * 4 */
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
+ nsyms = dur / APHY_SYMBOL_TIME;
+ mac_len =
+ ((nsyms * kNdps) -
+ ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
+ } else if (is_ofdm_rate(ratespec)) {
+ dur -= APHY_PREAMBLE_TIME;
+ dur -= APHY_SIGNAL_TIME;
+ /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
+ Ndps = rate * 2;
+ nsyms = dur / APHY_SYMBOL_TIME;
+ mac_len =
+ ((nsyms * Ndps) -
+ (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
} else {
- brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
+ if (preamble_type & BRCMS_SHORT_PREAMBLE)
+ dur -= BPHY_PLCP_SHORT_TIME;
+ else
+ dur -= BPHY_PLCP_TIME;
+ mac_len = dur * rate;
+ /* divide out factor of 2 in rate (1/2 mbps) */
+ mac_len = mac_len / 8 / 2;
}
- return;
+ return mac_len;
}
-/* Rate: 802.11 rate code, length: PSDU length in octets */
-static void brcms_c_compute_mimo_plcp(ratespec_t rspec, uint length, u8 *plcp)
+/*
+ * Return true if the specified rate is supported by the specified band.
+ * BRCM_BAND_AUTO indicates the current band.
+ */
+static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
+ bool verbose)
{
- u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
- plcp[0] = mcs;
- if (RSPEC_IS40MHZ(rspec) || (mcs == 32))
- plcp[0] |= MIMO_PLCP_40MHZ;
- BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
- plcp[3] = RSPEC_MIMOPLCP3(rspec); /* rspec already holds this byte */
- plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
- plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
- plcp[5] = 0;
+ struct brcms_c_rateset *hw_rateset;
+ uint i;
+
+ if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))
+ hw_rateset = &wlc->band->hw_rateset;
+ else if (wlc->pub->_nbands > 1)
+ hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
+ else
+ /* other band specified and we are a single band device */
+ return false;
+
+ /* check if this is a mimo rate */
+ if (is_mcs_rate(rspec)) {
+ if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)
+ goto error;
+
+ return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
+ }
+
+ for (i = 0; i < hw_rateset->count; i++)
+ if (hw_rateset->rates[i] == rspec2rate(rspec))
+ return true;
+ error:
+ if (verbose)
+ wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
+ "not in hw_rateset\n", wlc->pub->unit, rspec);
+
+ return false;
}
-/* Rate: 802.11 rate code, length: PSDU length in octets */
-static void
-brcms_c_compute_ofdm_plcp(ratespec_t rspec, u32 length, u8 *plcp)
+static u32
+mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
+ u32 int_val)
{
- u8 rate_signal;
- u32 tmp = 0;
- int rate = RSPEC2RATE(rspec);
+ u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
+ u8 rate = int_val & NRATE_RATE_MASK;
+ u32 rspec;
+ bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
+ bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
+ bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
+ == NRATE_OVERRIDE_MCS_ONLY);
+ int bcmerror = 0;
- /* encode rate per 802.11a-1999 sec 17.3.4.1, with lsb transmitted first */
- rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
- memset(plcp, 0, D11_PHY_HDR_LEN);
- D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
+ if (!ismcs)
+ return (u32) rate;
- tmp = (length & 0xfff) << 5;
- plcp[2] |= (tmp >> 16) & 0xff;
- plcp[1] |= (tmp >> 8) & 0xff;
- plcp[0] |= tmp & 0xff;
+ /* validate the combination of rate/mcs/stf is allowed */
+ if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) {
+ /* mcs only allowed when nmode */
+ if (stf > PHY_TXC1_MODE_SDM) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
- return;
+ /* mcs 32 is a special case, DUP mode 40 only */
+ if (rate == 32) {
+ if (!CHSPEC_IS40(wlc->home_chanspec) ||
+ ((stf != PHY_TXC1_MODE_SISO)
+ && (stf != PHY_TXC1_MODE_CDD))) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
+ "32\n", wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ /* mcs > 7 must use stf SDM */
+ } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
+ /* mcs > 7 must use stf SDM */
+ if (stf != PHY_TXC1_MODE_SDM) {
+ BCMMSG(wlc->wiphy, "wl%d: enabling "
+ "SDM mode for mcs %d\n",
+ wlc->pub->unit, rate);
+ stf = PHY_TXC1_MODE_SDM;
+ }
+ } else {
+ /*
+ * MCS 0-7 may use SISO, CDD, and for
+ * phy_rev >= 3 STBC
+ */
+ if ((stf > PHY_TXC1_MODE_STBC) ||
+ (!BRCMS_STBC_CAP_PHY(wlc)
+ && (stf == PHY_TXC1_MODE_STBC))) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
+ "\n", wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ }
+ } else if (is_ofdm_rate(rate)) {
+ if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ } else if (is_cck_rate(rate)) {
+ if ((cur_band->bandtype != BRCM_BAND_2G)
+ || (stf != PHY_TXC1_MODE_SISO)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ } else {
+ wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
+ wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+ /* make sure multiple antennae are available for non-siso rates */
+ if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
+ wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
+ "request\n", wlc->pub->unit, __func__);
+ bcmerror = -EINVAL;
+ goto done;
+ }
+
+ rspec = rate;
+ if (ismcs) {
+ rspec |= RSPEC_MIMORATE;
+ /* For STBC populate the STC field of the ratespec */
+ if (stf == PHY_TXC1_MODE_STBC) {
+ u8 stc;
+ stc = 1; /* Nss for single stream is always 1 */
+ rspec |= (stc << RSPEC_STC_SHIFT);
+ }
+ }
+
+ rspec |= (stf << RSPEC_STF_SHIFT);
+
+ if (override_mcs_only)
+ rspec |= RSPEC_OVERRIDE_MCS_ONLY;
+
+ if (issgi)
+ rspec |= RSPEC_SHORT_GI;
+
+ if ((rate != 0)
+ && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))
+ return rate;
+
+ return rspec;
+done:
+ return rate;
}
/*
@@ -3426,8 +6693,9 @@ static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
break;
default:
- wiphy_err(wlc->wiphy, "brcms_c_cck_plcp_set: unsupported rate %d"
- "\n", rate_500);
+ wiphy_err(wlc->wiphy,
+ "brcms_c_cck_plcp_set: unsupported rate %d\n",
+ rate_500);
rate_500 = BRCM_RATE_1M;
usec = length << 3;
break;
@@ -3445,45 +6713,60 @@ static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
}
/* Rate: 802.11 rate code, length: PSDU length in octets */
-static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, ratespec_t rspec,
- uint length, u8 *plcp)
+static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)
{
- int rate = RSPEC2RATE(rspec);
-
- brcms_c_cck_plcp_set(wlc, rate, length, plcp);
+ u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);
+ plcp[0] = mcs;
+ if (rspec_is40mhz(rspec) || (mcs == 32))
+ plcp[0] |= MIMO_PLCP_40MHZ;
+ BRCMS_SET_MIMO_PLCP_LEN(plcp, length);
+ plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */
+ plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */
+ plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */
+ plcp[5] = 0;
}
-/* brcms_c_compute_frame_dur()
- *
- * Calculate the 802.11 MAC header DUR field for MPDU
- * DUR for a single frame = 1 SIFS + 1 ACK
- * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time
- *
- * rate MPDU rate in unit of 500kbps
- * next_frag_len next MPDU length in bytes
- * preamble_type use short/GF or long/MM PLCP header
- */
-static u16
-brcms_c_compute_frame_dur(struct brcms_c_info *wlc, ratespec_t rate,
- u8 preamble_type, uint next_frag_len)
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void
+brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)
{
- u16 dur, sifs;
+ u8 rate_signal;
+ u32 tmp = 0;
+ int rate = rspec2rate(rspec);
- sifs = SIFS(wlc->band);
+ /*
+ * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb
+ * transmitted first
+ */
+ rate_signal = rate_info[rate] & BRCMS_RATE_MASK;
+ memset(plcp, 0, D11_PHY_HDR_LEN);
+ D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);
- dur = sifs;
- dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);
+ tmp = (length & 0xfff) << 5;
+ plcp[2] |= (tmp >> 16) & 0xff;
+ plcp[1] |= (tmp >> 8) & 0xff;
+ plcp[0] |= tmp & 0xff;
+}
- if (next_frag_len) {
- /* Double the current DUR to get 2 SIFS + 2 ACKs */
- dur *= 2;
- /* add another SIFS and the frag time */
- dur += sifs;
- dur +=
- (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,
- next_frag_len);
- }
- return dur;
+/* Rate: 802.11 rate code, length: PSDU length in octets */
+static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,
+ uint length, u8 *plcp)
+{
+ int rate = rspec2rate(rspec);
+
+ brcms_c_cck_plcp_set(wlc, rate, length, plcp);
+}
+
+static void
+brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,
+ uint length, u8 *plcp)
+{
+ if (is_mcs_rate(rspec))
+ brcms_c_compute_mimo_plcp(rspec, length, plcp);
+ else if (is_ofdm_rate(rspec))
+ brcms_c_compute_ofdm_plcp(rspec, length, plcp);
+ else
+ brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);
}
/* brcms_c_compute_rtscts_dur()
@@ -3499,20 +6782,22 @@ brcms_c_compute_frame_dur(struct brcms_c_info *wlc, ratespec_t rate,
*/
u16
brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
- ratespec_t rts_rate,
- ratespec_t frame_rate, u8 rts_preamble_type,
+ u32 rts_rate,
+ u32 frame_rate, u8 rts_preamble_type,
u8 frame_preamble_type, uint frame_len, bool ba)
{
u16 dur, sifs;
- sifs = SIFS(wlc->band);
+ sifs = get_sifs(wlc->band);
- if (!cts_only) { /* RTS/CTS */
+ if (!cts_only) {
+ /* RTS/CTS */
dur = 3 * sifs;
dur +=
(u16) brcms_c_calc_cts_time(wlc, rts_rate,
rts_preamble_type);
- } else { /* CTS-TO-SELF */
+ } else {
+ /* CTS-TO-SELF */
dur = 2 * sifs;
}
@@ -3530,7 +6815,7 @@ brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
return dur;
}
-u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, ratespec_t rspec)
+static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
{
u16 phyctl1 = 0;
u16 bw;
@@ -3538,7 +6823,7 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, ratespec_t rspec)
if (BRCMS_ISLCNPHY(wlc->band)) {
bw = PHY_TXC1_BW_20MHZ;
} else {
- bw = RSPEC_GET_BW(rspec);
+ bw = rspec_get_bw(rspec);
/* 10Mhz is not supported yet */
if (bw < PHY_TXC1_BW_20MHZ) {
wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
@@ -3547,23 +6832,26 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, ratespec_t rspec)
}
}
- if (IS_MCS(rspec)) {
+ if (is_mcs_rate(rspec)) {
uint mcs = rspec & RSPEC_RATE_MASK;
- /* bw, stf, coding-type is part of RSPEC_PHYTXBYTE2 returns */
- phyctl1 = RSPEC_PHYTXBYTE2(rspec);
+ /* bw, stf, coding-type is part of rspec_phytxbyte2 returns */
+ phyctl1 = rspec_phytxbyte2(rspec);
/* set the upper byte of phyctl1 */
phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);
- } else if (IS_CCK(rspec) && !BRCMS_ISLCNPHY(wlc->band)
+ } else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band)
&& !BRCMS_ISSSLPNPHY(wlc->band)) {
- /* In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate */
- /* Eventually MIMOPHY would also be converted to this format */
+ /*
+ * In CCK mode LPPHY overloads OFDM Modulation bits with CCK
+ * Data Rate. Eventually MIMOPHY would also be converted to
+ * this format
+ */
/* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
- phyctl1 = (bw | (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
+ phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
} else { /* legacy OFDM/CCK */
s16 phycfg;
/* get the phyctl byte from rate phycfg table */
- phycfg = brcms_c_rate_legacy_phyctl(RSPEC2RATE(rspec));
+ phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));
if (phycfg == -1) {
wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
"legacy OFDM/CCK rate\n");
@@ -3572,58 +6860,11 @@ u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, ratespec_t rspec)
/* set the upper byte of phyctl1 */
phyctl1 =
(bw | (phycfg << 8) |
- (RSPEC_STF(rspec) << PHY_TXC1_MODE_SHIFT));
+ (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));
}
return phyctl1;
}
-ratespec_t
-brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, ratespec_t rspec,
- bool use_rspec, u16 mimo_ctlchbw)
-{
- ratespec_t rts_rspec = 0;
-
- if (use_rspec) {
- /* use frame rate as rts rate */
- rts_rspec = rspec;
-
- } else if (wlc->band->gmode && wlc->protection->_g && !IS_CCK(rspec)) {
- /* Use 11Mbps as the g protection RTS target rate and fallback.
- * Use the BRCMS_BASIC_RATE() lookup to find the best basic rate
- * under the target in case 11 Mbps is not Basic.
- * 6 and 9 Mbps are not usually selected by rate selection, but even
- * if the OFDM rate we are protecting is 6 or 9 Mbps, 11 is more robust.
- */
- rts_rspec = BRCMS_BASIC_RATE(wlc, BRCM_RATE_11M);
- } else {
- /* calculate RTS rate and fallback rate based on the frame rate
- * RTS must be sent at a basic rate since it is a
- * control frame, sec 9.6 of 802.11 spec
- */
- rts_rspec = BRCMS_BASIC_RATE(wlc, rspec);
- }
-
- if (BRCMS_PHY_11N_CAP(wlc->band)) {
- /* set rts txbw to correct side band */
- rts_rspec &= ~RSPEC_BW_MASK;
-
- /* if rspec/rspec_fallback is 40MHz, then send RTS on both 20MHz channel
- * (DUP), otherwise send RTS on control channel
- */
- if (RSPEC_IS40MHZ(rspec) && !IS_CCK(rts_rspec))
- rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
- else
- rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
-
- /* pick siso/cdd as default for ofdm */
- if (IS_OFDM(rts_rspec)) {
- rts_rspec &= ~RSPEC_STF_MASK;
- rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
- }
- }
- return rts_rspec;
-}
-
/*
* Add struct d11txh, struct cck_phy_hdr.
*
@@ -3636,8 +6877,7 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, ratespec_t rspec,
static u16
brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
struct sk_buff *p, struct scb *scb, uint frag,
- uint nfrags, uint queue, uint next_frag_len,
- struct wsec_key *key, ratespec_t rspec_override)
+ uint nfrags, uint queue, uint next_frag_len)
{
struct ieee80211_hdr *h;
struct d11txh *txh;
@@ -3645,8 +6885,8 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
int len, phylen, rts_phylen;
u16 mch, phyctl, xfts, mainrates;
u16 seq = 0, mcl = 0, status = 0, frameid = 0;
- ratespec_t rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M }, rts_rspec[2] = {
- BRCM_RATE_1M, BRCM_RATE_1M};
+ u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
+ u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };
bool use_rts = false;
bool use_cts = false;
bool use_rifs = false;
@@ -3657,7 +6897,6 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
struct ieee80211_rts *rts = NULL;
bool qos;
uint ac;
- u32 rate_val[2];
bool hwtkmic = false;
u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
#define ANTCFG_NONE 0xFF
@@ -3668,7 +6907,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
struct ieee80211_tx_rate *txrate[2];
int k;
struct ieee80211_tx_info *tx_info;
- bool is_mcs[2];
+ bool is_mcs;
u16 mimo_txbw;
u8 mimo_preamble_type;
@@ -3680,15 +6919,6 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
len = brcmu_pkttotlen(p);
phylen = len + FCS_LEN;
- /* If WEP enabled, add room in phylen for the additional bytes of
- * ICV which MAC generates. We do NOT add the additional bytes to
- * the packet itself, thus phylen = packet length + ICV_LEN + FCS_LEN
- * in this case
- */
- if (key) {
- phylen += key->icv_len;
- }
-
/* Get tx_info */
tx_info = IEEE80211_SKB_CB(p);
@@ -3704,17 +6934,16 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
/* non-AP STA should never use BCMC queue */
if (queue == TX_BCMC_FIFO) {
wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == "
- "TX_BCMC!\n", BRCMS_UNIT(wlc), __func__);
+ "TX_BCMC!\n", wlc->pub->unit, __func__);
frameid = bcmc_fid_generate(wlc, NULL, txh);
} else {
/* Increment the counter for first fragment */
- if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) {
- SCB_SEQNUM(scb, p->priority)++;
- }
+ if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+ scb->seqnum[p->priority]++;
/* extract fragment number from frame first */
- seq = le16_to_cpu(seq) & FRAGNUM_MASK;
- seq |= (SCB_SEQNUM(scb, p->priority) << SEQNUM_SHIFT);
+ seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;
+ seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);
h->seq_ctrl = cpu_to_le16(seq);
frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |
@@ -3724,25 +6953,26 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
frameid |= queue & TXFID_QUEUE_MASK;
/* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */
- if (SCB_PS(scb) || ieee80211_is_beacon(h->frame_control))
+ if (ieee80211_is_beacon(h->frame_control))
mcl |= TXC_IGNOREPMQ;
txrate[0] = tx_info->control.rates;
txrate[1] = txrate[0] + 1;
- /* if rate control algorithm didn't give us a fallback rate, use the primary rate */
- if (txrate[1]->idx < 0) {
+ /*
+ * if rate control algorithm didn't give us a fallback
+ * rate, use the primary rate
+ */
+ if (txrate[1]->idx < 0)
txrate[1] = txrate[0];
- }
for (k = 0; k < hw->max_rates; k++) {
- is_mcs[k] =
- txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
- if (!is_mcs[k]) {
+ is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;
+ if (!is_mcs) {
if ((txrate[k]->idx >= 0)
&& (txrate[k]->idx <
hw->wiphy->bands[tx_info->band]->n_bitrates)) {
- rate_val[k] =
+ rspec[k] =
hw->wiphy->bands[tx_info->band]->
bitrates[txrate[k]->idx].hw_value;
short_preamble[k] =
@@ -3750,13 +6980,17 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ?
true : false;
} else {
- rate_val[k] = BRCM_RATE_1M;
+ rspec[k] = BRCM_RATE_1M;
}
} else {
- rate_val[k] = txrate[k]->idx;
+ rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band,
+ NRATE_MCS_INUSE | txrate[k]->idx);
}
- /* Currently only support same setting for primay and fallback rates.
- * Unify flags for each rate into a single value for the frame
+
+ /*
+ * Currently only support same setting for primay and
+ * fallback rates. Unify flags for each rate into a
+ * single value for the frame
*/
use_rts |=
txrate[k]->
@@ -3765,13 +6999,13 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
txrate[k]->
flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;
- if (is_mcs[k])
- rate_val[k] |= NRATE_MCS_INUSE;
- rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, rate_val[k]);
-
- /* (1) RATE: determine and validate primary rate and fallback rates */
- if (!RSPEC_ACTIVE(rspec[k])) {
+ /*
+ * (1) RATE:
+ * determine and validate primary rate
+ * and fallback rates
+ */
+ if (!rspec_active(rspec[k])) {
rspec[k] = BRCM_RATE_1M;
} else {
if (!is_multicast_ether_addr(h->addr1)) {
@@ -3784,41 +7018,49 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
phyctl1_stf = wlc->stf->ss_opmode;
- if (N_ENAB(wlc->pub)) {
+ if (wlc->pub->_n_enab & SUPPORT_11N) {
for (k = 0; k < hw->max_rates; k++) {
- /* apply siso/cdd to single stream mcs's or ofdm if rspec is auto selected */
- if (((IS_MCS(rspec[k]) &&
- IS_SINGLE_STREAM(rspec[k] & RSPEC_RATE_MASK)) ||
- IS_OFDM(rspec[k]))
+ /*
+ * apply siso/cdd to single stream mcs's or ofdm
+ * if rspec is auto selected
+ */
+ if (((is_mcs_rate(rspec[k]) &&
+ is_single_stream(rspec[k] & RSPEC_RATE_MASK)) ||
+ is_ofdm_rate(rspec[k]))
&& ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)
|| !(rspec[k] & RSPEC_OVERRIDE))) {
rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);
/* For SISO MCS use STBC if possible */
- if (IS_MCS(rspec[k])
+ if (is_mcs_rate(rspec[k])
&& BRCMS_STF_SS_STBC_TX(wlc, scb)) {
u8 stc;
- stc = 1; /* Nss for single stream is always 1 */
- rspec[k] |=
- (PHY_TXC1_MODE_STBC <<
- RSPEC_STF_SHIFT) | (stc <<
- RSPEC_STC_SHIFT);
+ /* Nss for single stream is always 1 */
+ stc = 1;
+ rspec[k] |= (PHY_TXC1_MODE_STBC <<
+ RSPEC_STF_SHIFT) |
+ (stc << RSPEC_STC_SHIFT);
} else
rspec[k] |=
(phyctl1_stf << RSPEC_STF_SHIFT);
}
- /* Is the phy configured to use 40MHZ frames? If so then pick the desired txbw */
- if (CHSPEC_WLC_BW(wlc->chanspec) == BRCMS_40_MHZ) {
+ /*
+ * Is the phy configured to use 40MHZ frames? If
+ * so then pick the desired txbw
+ */
+ if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) {
/* default txbw is 20in40 SB */
mimo_ctlchbw = mimo_txbw =
- CHSPEC_SB_UPPER(BRCMS_BAND_PI_RADIO_CHANSPEC)
+ CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
+ wlc->band->pi))
? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
- if (IS_MCS(rspec[k])) {
+ if (is_mcs_rate(rspec[k])) {
/* mcs 32 must be 40b/w DUP */
- if ((rspec[k] & RSPEC_RATE_MASK) == 32) {
+ if ((rspec[k] & RSPEC_RATE_MASK)
+ == 32) {
mimo_txbw =
PHY_TXC1_BW_40MHZ_DUP;
/* use override */
@@ -3827,66 +7069,61 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
/* else check if dst is using 40 Mhz */
else if (scb->flags & SCB_IS40)
mimo_txbw = PHY_TXC1_BW_40MHZ;
- } else if (IS_OFDM(rspec[k])) {
+ } else if (is_ofdm_rate(rspec[k])) {
if (wlc->ofdm_40txbw != AUTO)
mimo_txbw = wlc->ofdm_40txbw;
- } else {
- if (wlc->cck_40txbw != AUTO)
- mimo_txbw = wlc->cck_40txbw;
+ } else if (wlc->cck_40txbw != AUTO) {
+ mimo_txbw = wlc->cck_40txbw;
}
} else {
- /* mcs32 is 40 b/w only.
- * This is possible for probe packets on a STA during SCAN
+ /*
+ * mcs32 is 40 b/w only.
+ * This is possible for probe packets on
+ * a STA during SCAN
*/
- if ((rspec[k] & RSPEC_RATE_MASK) == 32) {
+ if ((rspec[k] & RSPEC_RATE_MASK) == 32)
/* mcs 0 */
rspec[k] = RSPEC_MIMORATE;
- }
+
mimo_txbw = PHY_TXC1_BW_20MHZ;
}
/* Set channel width */
rspec[k] &= ~RSPEC_BW_MASK;
- if ((k == 0) || ((k > 0) && IS_MCS(rspec[k])))
+ if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k])))
rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);
else
rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
- /* Set Short GI */
-#ifdef NOSGIYET
- if (IS_MCS(rspec[k])
- && (txrate[k]->flags & IEEE80211_TX_RC_SHORT_GI))
- rspec[k] |= RSPEC_SHORT_GI;
- else if (!(txrate[k]->flags & IEEE80211_TX_RC_SHORT_GI))
- rspec[k] &= ~RSPEC_SHORT_GI;
-#else
+ /* Disable short GI, not supported yet */
rspec[k] &= ~RSPEC_SHORT_GI;
-#endif
mimo_preamble_type = BRCMS_MM_PREAMBLE;
if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)
mimo_preamble_type = BRCMS_GF_PREAMBLE;
if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
- && (!IS_MCS(rspec[k]))) {
+ && (!is_mcs_rate(rspec[k]))) {
wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
- "RC_MCS != IS_MCS(rspec)\n",
- BRCMS_UNIT(wlc), __func__);
+ "RC_MCS != is_mcs_rate(rspec)\n",
+ wlc->pub->unit, __func__);
}
- if (IS_MCS(rspec[k])) {
+ if (is_mcs_rate(rspec[k])) {
preamble_type[k] = mimo_preamble_type;
- /* if SGI is selected, then forced mm for single stream */
+ /*
+ * if SGI is selected, then forced mm
+ * for single stream
+ */
if ((rspec[k] & RSPEC_SHORT_GI)
- && IS_SINGLE_STREAM(rspec[k] &
- RSPEC_RATE_MASK)) {
+ && is_single_stream(rspec[k] &
+ RSPEC_RATE_MASK))
preamble_type[k] = BRCMS_MM_PREAMBLE;
- }
}
/* should be better conditionalized */
- if (!IS_MCS(rspec[0])
+ if (!is_mcs_rate(rspec[0])
&& (tx_info->control.rates[0].
flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))
preamble_type[k] = BRCMS_SHORT_PREAMBLE;
@@ -3898,7 +7135,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);
/* for nphy, stf of ofdm frames must follow policies */
- if (BRCMS_ISNPHY(wlc->band) && IS_OFDM(rspec[k])) {
+ if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) {
rspec[k] &= ~RSPEC_STF_MASK;
rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;
}
@@ -3923,13 +7160,13 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
plcp_fallback, sizeof(txh->FragPLCPFallback));
/* Length field now put in CCK FBR CRC field */
- if (IS_CCK(rspec[1])) {
+ if (is_cck_rate(rspec[1])) {
txh->FragPLCPFallback[4] = phylen & 0xff;
txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;
}
/* MIMO-RATE: need validation ?? */
- mainrates = IS_OFDM(rspec[0]) ?
+ mainrates = is_ofdm_rate(rspec[0]) ?
D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :
plcp[0];
@@ -3968,10 +7205,10 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
if (!is_multicast_ether_addr(h->addr1))
mcl |= TXC_IMMEDACK;
- if (BAND_5G(wlc->band->bandtype))
+ if (wlc->band->bandtype == BRCM_BAND_5G)
mcl |= TXC_FREQBAND_5G;
- if (CHSPEC_IS40(BRCMS_BAND_PI_RADIO_CHANSPEC))
+ if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi)))
mcl |= TXC_BW_40;
/* set AMIC bit if using hardware TKIP MIC */
@@ -3986,7 +7223,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
/* Set fallback rate preamble type */
if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||
(preamble_type[1] == BRCMS_GF_PREAMBLE)) {
- if (RSPEC2RATE(rspec[1]) != BRCM_RATE_1M)
+ if (rspec2rate(rspec[1]) != BRCM_RATE_1M)
mch |= TXC_PREAMBLE_DATA_FB_SHORT;
}
@@ -4002,12 +7239,14 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
/* TxFrameID */
txh->TxFrameID = cpu_to_le16(frameid);
- /* TxStatus, Note the case of recreating the first frag of a suppressed frame
- * then we may need to reset the retry cnt's via the status reg
+ /*
+ * TxStatus, Note the case of recreating the first frag of a suppressed
+ * frame then we may need to reset the retry cnt's via the status reg
*/
txh->TxStatus = cpu_to_le16(status);
- /* extra fields for ucode AMPDU aggregation, the new fields are added to
+ /*
+ * extra fields for ucode AMPDU aggregation, the new fields are added to
* the END of previous structure so that it's compatible in driver.
*/
txh->MaxNMpdus = cpu_to_le16(0);
@@ -4028,15 +7267,15 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
mimo_ctlchbw);
}
- if (!IS_OFDM(rts_rspec[0]) &&
- !((RSPEC2RATE(rts_rspec[0]) == BRCM_RATE_1M) ||
+ if (!is_ofdm_rate(rts_rspec[0]) &&
+ !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) ||
(wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;
mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;
}
- if (!IS_OFDM(rts_rspec[1]) &&
- !((RSPEC2RATE(rts_rspec[1]) == BRCM_RATE_1M) ||
+ if (!is_ofdm_rate(rts_rspec[1]) &&
+ !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) ||
(wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {
rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;
mch |= TXC_PREAMBLE_RTS_FB_SHORT;
@@ -4095,7 +7334,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
* low 8 bits: main frag rate/mcs,
* high 8 bits: rts/cts rate/mcs
*/
- mainrates |= (IS_OFDM(rts_rspec[0]) ?
+ mainrates |= (is_ofdm_rate(rts_rspec[0]) ?
D11A_PHY_HDR_GRATE(
(struct ofdm_phy_hdr *) rts_plcp) :
rts_plcp[0]) << 8;
@@ -4110,31 +7349,37 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
#ifdef SUPPORT_40MHZ
/* add null delimiter count */
- if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && IS_MCS(rspec)) {
+ if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec))
txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =
brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);
- }
+
#endif
- /* Now that RTS/RTS FB preamble types are updated, write the final value */
+ /*
+ * Now that RTS/RTS FB preamble types are updated, write
+ * the final value
+ */
txh->MacTxControlHigh = cpu_to_le16(mch);
- /* MainRates (both the rts and frag plcp rates have been calculated now) */
+ /*
+ * MainRates (both the rts and frag plcp rates have
+ * been calculated now)
+ */
txh->MainRates = cpu_to_le16(mainrates);
/* XtraFrameTypes */
- xfts = FRAMETYPE(rspec[1], wlc->mimoft);
- xfts |= (FRAMETYPE(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
- xfts |= (FRAMETYPE(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
- xfts |=
- CHSPEC_CHANNEL(BRCMS_BAND_PI_RADIO_CHANSPEC) << XFTS_CHANNEL_SHIFT;
+ xfts = frametype(rspec[1], wlc->mimoft);
+ xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);
+ xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);
+ xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) <<
+ XFTS_CHANNEL_SHIFT;
txh->XtraFrameTypes = cpu_to_le16(xfts);
/* PhyTxControlWord */
- phyctl = FRAMETYPE(rspec[0], wlc->mimoft);
+ phyctl = frametype(rspec[0], wlc->mimoft);
if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||
(preamble_type[0] == BRCMS_GF_PREAMBLE)) {
- if (RSPEC2RATE(rspec[0]) != BRCM_RATE_1M)
+ if (rspec2rate(rspec[0]) != BRCM_RATE_1M)
phyctl |= PHY_TXC_SHORT_HDR;
}
@@ -4159,18 +7404,18 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
}
/*
- * For mcs frames, if mixedmode(overloaded with long preamble) is going to be set,
- * fill in non-zero MModeLen and/or MModeFbrLen
- * it will be unnecessary if they are separated
+ * For mcs frames, if mixedmode(overloaded with long preamble)
+ * is going to be set, fill in non-zero MModeLen and/or
+ * MModeFbrLen it will be unnecessary if they are separated
*/
- if (IS_MCS(rspec[0]) &&
+ if (is_mcs_rate(rspec[0]) &&
(preamble_type[0] == BRCMS_MM_PREAMBLE)) {
u16 mmodelen =
brcms_c_calc_lsig_len(wlc, rspec[0], phylen);
txh->MModeLen = cpu_to_le16(mmodelen);
}
- if (IS_MCS(rspec[1]) &&
+ if (is_mcs_rate(rspec[1]) &&
(preamble_type[1] == BRCMS_MM_PREAMBLE)) {
u16 mmodefbrlen =
brcms_c_calc_lsig_len(wlc, rspec[1], phylen);
@@ -4179,11 +7424,11 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
}
ac = skb_get_queue_mapping(p);
- if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) {
+ if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) {
uint frag_dur, dur, dur_fallback;
/* WME: Update TXOP threshold */
- if ((!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) && (frag == 0)) {
+ if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {
frag_dur =
brcms_c_calc_frame_time(wlc, rspec[0],
preamble_type[0], phylen);
@@ -4220,40 +7465,44 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
}
/* NEED to set TxFesTimeNormal (hard) */
txh->TxFesTimeNormal = cpu_to_le16((u16) dur);
- /* NEED to set fallback rate version of TxFesTimeNormal (hard) */
+ /*
+ * NEED to set fallback rate version of
+ * TxFesTimeNormal (hard)
+ */
txh->TxFesTimeFallback =
cpu_to_le16((u16) dur_fallback);
- /* update txop byte threshold (txop minus intraframe overhead) */
+ /*
+ * update txop byte threshold (txop minus intraframe
+ * overhead)
+ */
if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {
- {
- uint newfragthresh;
-
+ uint newfragthresh;
+
+ newfragthresh =
+ brcms_c_calc_frame_len(wlc,
+ rspec[0], preamble_type[0],
+ (wlc->edcf_txop[ac] -
+ (dur - frag_dur)));
+ /* range bound the fragthreshold */
+ if (newfragthresh < DOT11_MIN_FRAG_LEN)
newfragthresh =
- brcms_c_calc_frame_len(wlc,
- rspec[0], preamble_type[0],
- (wlc->edcf_txop[ac] -
- (dur - frag_dur)));
- /* range bound the fragthreshold */
- if (newfragthresh < DOT11_MIN_FRAG_LEN)
- newfragthresh =
- DOT11_MIN_FRAG_LEN;
- else if (newfragthresh >
- wlc->usr_fragthresh)
- newfragthresh =
- wlc->usr_fragthresh;
- /* update the fragthresh and do txc update */
- if (wlc->fragthresh[queue] !=
- (u16) newfragthresh) {
- wlc->fragthresh[queue] =
- (u16) newfragthresh;
- }
- }
- } else
+ DOT11_MIN_FRAG_LEN;
+ else if (newfragthresh >
+ wlc->usr_fragthresh)
+ newfragthresh =
+ wlc->usr_fragthresh;
+ /* update the fragthresh and do txc update */
+ if (wlc->fragthresh[queue] !=
+ (u16) newfragthresh)
+ wlc->fragthresh[queue] =
+ (u16) newfragthresh;
+ } else {
wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
"for rate %d\n",
wlc->pub->unit, fifo_names[queue],
- RSPEC2RATE(rspec[0]));
+ rspec2rate(rspec[0]));
+ }
if (dur > wlc->edcf_txop[ac])
wiphy_err(wlc->wiphy, "wl%d: %s: %s txop "
@@ -4268,225 +7517,191 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
return 0;
}
-void brcms_c_tbtt(struct brcms_c_info *wlc)
+void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
+ struct ieee80211_hw *hw)
{
- struct brcms_bss_cfg *cfg = wlc->cfg;
-
- if (!cfg->BSS) {
- /* DirFrmQ is now valid...defer setting until end of ATIM window */
- wlc->qvalid |= MCMD_DIRFRMQVAL;
- }
-}
+ u8 prio;
+ uint fifo;
+ struct scb *scb = &wlc->pri_scb;
+ struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
-static void brcms_c_war16165(struct brcms_c_info *wlc, bool tx)
-{
- if (tx) {
- /* the post-increment is used in STAY_AWAKE macro */
- if (wlc->txpend16165war++ == 0)
- brcms_c_set_ps_ctrl(wlc);
- } else {
- wlc->txpend16165war--;
- if (wlc->txpend16165war == 0)
- brcms_c_set_ps_ctrl(wlc);
- }
+ /*
+ * 802.11 standard requires management traffic
+ * to go at highest priority
+ */
+ prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
+ MAXPRIO;
+ fifo = prio2fifo[prio];
+ if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0))
+ return;
+ brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio));
+ brcms_c_send_q(wlc);
}
-/* process an individual struct tx_status */
-bool
-brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs, u32 frm_tx2)
+void brcms_c_send_q(struct brcms_c_info *wlc)
{
- struct sk_buff *p;
- uint queue;
- struct d11txh *txh;
- struct scb *scb = NULL;
- bool free_pdu;
- int tx_rts, tx_frame_count, tx_rts_count;
- uint totlen, supr_status;
- bool lastframe;
- struct ieee80211_hdr *h;
- u16 mcl;
+ struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
+ int prec;
+ u16 prec_map;
+ int err = 0, i, count;
+ uint fifo;
+ struct brcms_txq_info *qi = wlc->pkt_queue;
+ struct pktq *q = &qi->q;
struct ieee80211_tx_info *tx_info;
- struct ieee80211_tx_rate *txrate;
- int i;
- (void)(frm_tx2); /* Compiler reference to avoid unused variable warning */
+ prec_map = wlc->tx_prec_map;
- /* discard intermediate indications for ucode with one legitimate case:
- * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
- * tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
- * transmission count)
+ /* Send all the enq'd pkts that we can.
+ * Dequeue packets with precedence with empty HW fifo only
*/
- if (!(txs->status & TX_STATUS_AMPDU)
- && (txs->status & TX_STATUS_INTERMEDIATE)) {
- wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n",
- __func__);
- return false;
- }
+ while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
+ tx_info = IEEE80211_SKB_CB(pkt[0]);
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
+ } else {
+ count = 1;
+ err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
+ if (!err) {
+ for (i = 0; i < count; i++)
+ brcms_c_txfifo(wlc, fifo, pkt[i], true,
+ 1);
+ }
+ }
- queue = txs->frameid & TXFID_QUEUE_MASK;
- if (queue >= NFIFO) {
- p = NULL;
- goto fatal;
+ if (err == -EBUSY) {
+ brcmu_pktq_penq_head(q, prec, pkt[0]);
+ /*
+ * If send failed due to any other reason than a
+ * change in HW FIFO condition, quit. Otherwise,
+ * read the new prec_map!
+ */
+ if (prec_map == wlc->tx_prec_map)
+ break;
+ prec_map = wlc->tx_prec_map;
+ }
}
+}
- p = GETNEXTTXP(wlc, queue);
- if (BRCMS_WAR16165(wlc))
- brcms_c_war16165(wlc, false);
- if (p == NULL)
- goto fatal;
+void
+brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
+ bool commit, s8 txpktpend)
+{
+ u16 frameid = INVALIDFID;
+ struct d11txh *txh;
txh = (struct d11txh *) (p->data);
- mcl = le16_to_cpu(txh->MacTxControlLow);
-
- if (txs->phyerr) {
- if (WL_ERROR_ON()) {
- wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n",
- txs->phyerr, txh->MainRates);
- brcms_c_print_txdesc(txh);
- }
- brcms_c_print_txstatus(txs);
- }
- if (txs->frameid != cpu_to_le16(txh->TxFrameID))
- goto fatal;
- tx_info = IEEE80211_SKB_CB(p);
- h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
-
- if (tx_info->control.sta)
- scb = (struct scb *)tx_info->control.sta->drv_priv;
+ /* When a BC/MC frame is being committed to the BCMC fifo
+ * via DMA (NOT PIO), update ucode or BSS info as appropriate.
+ */
+ if (fifo == TX_BCMC_FIFO)
+ frameid = le16_to_cpu(txh->TxFrameID);
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
- brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
- return false;
+ /*
+ * Bump up pending count for if not using rpc. If rpc is
+ * used, this will be handled in brcms_b_txfifo()
+ */
+ if (commit) {
+ wlc->core->txpktpend[fifo] += txpktpend;
+ BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
+ txpktpend, wlc->core->txpktpend[fifo]);
}
- supr_status = txs->status & TX_STATUS_SUPR_MASK;
- if (supr_status == TX_STATUS_SUPR_BADCH)
- BCMMSG(wlc->wiphy,
- "%s: Pkt tx suppressed, possibly channel %d\n",
- __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec));
+ /* Commit BCMC sequence number in the SHM frame ID location */
+ if (frameid != INVALIDFID) {
+ /*
+ * To inform the ucode of the last mcast frame posted
+ * so that it can clear moredata bit
+ */
+ brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
+ }
- tx_rts = cpu_to_le16(txh->MacTxControlLow) & TXC_SENDRTS;
- tx_frame_count =
- (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;
- tx_rts_count =
- (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT;
+ if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0)
+ wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
+}
- lastframe = !ieee80211_has_morefrags(h->frame_control);
+u32
+brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
+ bool use_rspec, u16 mimo_ctlchbw)
+{
+ u32 rts_rspec = 0;
- if (!lastframe) {
- wiphy_err(wlc->wiphy, "Not last frame!\n");
- } else {
- /*
- * Set information to be consumed by Minstrel ht.
- *
- * The "fallback limit" is the number of tx attempts a given
- * MPDU is sent at the "primary" rate. Tx attempts beyond that
- * limit are sent at the "secondary" rate.
- * A 'short frame' does not exceed RTS treshold.
+ if (use_rspec)
+ /* use frame rate as rts rate */
+ rts_rspec = rspec;
+ else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec))
+ /* Use 11Mbps as the g protection RTS target rate and fallback.
+ * Use the brcms_basic_rate() lookup to find the best basic rate
+ * under the target in case 11 Mbps is not Basic.
+ * 6 and 9 Mbps are not usually selected by rate selection, but
+ * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11
+ * is more robust.
*/
- u16 sfbl, /* Short Frame Rate Fallback Limit */
- lfbl, /* Long Frame Rate Fallback Limit */
- fbl;
+ rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M);
+ else
+ /* calculate RTS rate and fallback rate based on the frame rate
+ * RTS must be sent at a basic rate since it is a
+ * control frame, sec 9.6 of 802.11 spec
+ */
+ rts_rspec = brcms_basic_rate(wlc, rspec);
- if (queue < AC_COUNT) {
- sfbl = BRCMS_WME_RETRY_SFB_GET(wlc, wme_fifo2ac[queue]);
- lfbl = BRCMS_WME_RETRY_LFB_GET(wlc, wme_fifo2ac[queue]);
- } else {
- sfbl = wlc->SFBL;
- lfbl = wlc->LFBL;
- }
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ /* set rts txbw to correct side band */
+ rts_rspec &= ~RSPEC_BW_MASK;
- txrate = tx_info->status.rates;
- if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
- fbl = lfbl;
+ /*
+ * if rspec/rspec_fallback is 40MHz, then send RTS on both
+ * 20MHz channel (DUP), otherwise send RTS on control channel
+ */
+ if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec))
+ rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);
else
- fbl = sfbl;
-
- ieee80211_tx_info_clear_status(tx_info);
-
- if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) {
- /* rate selection requested a fallback rate and we used it */
- txrate[0].count = fbl;
- txrate[1].count = tx_frame_count - fbl;
- } else {
- /* rate selection did not request fallback rate, or we didn't need it */
- txrate[0].count = tx_frame_count;
- /* rc80211_minstrel.c:minstrel_tx_status() expects unused rates to be marked with idx = -1 */
- txrate[1].idx = -1;
- txrate[1].count = 0;
- }
+ rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);
- /* clear the rest of the rates */
- for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {
- txrate[i].idx = -1;
- txrate[i].count = 0;
+ /* pick siso/cdd as default for ofdm */
+ if (is_ofdm_rate(rts_rspec)) {
+ rts_rspec &= ~RSPEC_STF_MASK;
+ rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);
}
-
- if (txs->status & TX_STATUS_ACK_RCV)
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
- }
-
- totlen = brcmu_pkttotlen(p);
- free_pdu = true;
-
- brcms_c_txfifo_complete(wlc, queue, 1);
-
- if (lastframe) {
- p->next = NULL;
- p->prev = NULL;
- /* remove PLCP & Broadcom tx descriptor header */
- skb_pull(p, D11_PHY_HDR_LEN);
- skb_pull(p, D11_TXH_LEN);
- ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
- } else {
- wiphy_err(wlc->wiphy, "%s: Not last frame => not calling "
- "tx_status\n", __func__);
}
-
- return false;
-
- fatal:
- if (p)
- brcmu_pkt_buf_free_skb(p);
-
- return true;
-
+ return rts_rspec;
}
void
brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
{
- TXPKTPENDDEC(wlc, fifo, txpktpend);
+ wlc->core->txpktpend[fifo] -= txpktpend;
BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend,
- TXPKTPENDGET(wlc, fifo));
+ wlc->core->txpktpend[fifo]);
/* There is more room; mark precedences related to this FIFO sendable */
- BRCMS_TX_FIFO_ENAB(wlc, fifo);
-
- /* Clear MHF2_TXBCMC_NOW flag if BCMC fifo has drained */
- if (AP_ENAB(wlc->pub) &&
- !TXPKTPENDGET(wlc, TX_BCMC_FIFO)) {
- brcms_c_mhf(wlc, MHF2, MHF2_TXBCMC_NOW, 0, BRCM_BAND_AUTO);
- }
+ wlc->tx_prec_map |= wlc->fifo2prec_map[fifo];
/* figure out which bsscfg is being worked on... */
}
/* Update beacon listen interval in shared memory */
-void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
+static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
{
- if (AP_ENAB(wlc->pub))
- return;
-
/* wake up every DTIM is the default */
if (wlc->bcn_li_dtim == 1)
- brcms_c_write_shm(wlc, M_BCN_LI, 0);
+ brcms_b_write_shm(wlc->hw, M_BCN_LI, 0);
else
- brcms_c_write_shm(wlc, M_BCN_LI,
+ brcms_b_write_shm(wlc->hw, M_BCN_LI,
(wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);
}
+static void
+brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
+ u32 *tsf_h_ptr)
+{
+ struct d11regs __iomem *regs = wlc_hw->regs;
+
+ /* read the tsf timer low, then high to get an atomic read */
+ *tsf_l_ptr = R_REG(&regs->tsf_timerlow);
+ *tsf_h_ptr = R_REG(&regs->tsf_timerhigh);
+}
+
/*
* recover 64bit TSF value from the 16bit TSF value in the rx header
* given the assumption that the TSF passed in header is within 65ms
@@ -4502,7 +7717,7 @@ void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
* are used. Finally, the tsf_h is read from the tsf register.
*/
static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
- struct brcms_d11rxhdr *rxh)
+ struct d11rxhdr *rxh)
{
u32 tsf_h, tsf_l;
u16 rx_tsf_0_15, rx_tsf_16_31;
@@ -4510,7 +7725,7 @@ static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,
brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);
rx_tsf_16_31 = (u16)(tsf_l >> 16);
- rx_tsf_0_15 = rxh->rxhdr.RxTSFTime;
+ rx_tsf_0_15 = rxh->RxTSFTime;
/*
* a greater tsf time indicates the low 16 bits of
@@ -4530,14 +7745,13 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
struct sk_buff *p,
struct ieee80211_rx_status *rx_status)
{
- struct brcms_d11rxhdr *wlc_rxh = (struct brcms_d11rxhdr *) rxh;
int preamble;
int channel;
- ratespec_t rspec;
+ u32 rspec;
unsigned char *plcp;
/* fill in TSF and flag its presence */
- rx_status->mactime = brcms_c_recover_tsf64(wlc, wlc_rxh);
+ rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh);
rx_status->flag |= RX_FLAG_MACTIME_MPDU;
channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
@@ -4552,22 +7766,23 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
}
- rx_status->signal = wlc_rxh->rssi; /* signal */
+ rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);
/* noise */
/* qual */
- rx_status->antenna = (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0; /* ant */
+ rx_status->antenna =
+ (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;
plcp = p->data;
rspec = brcms_c_compute_rspec(rxh, plcp);
- if (IS_MCS(rspec)) {
+ if (is_mcs_rate(rspec)) {
rx_status->rate_idx = rspec & RSPEC_RATE_MASK;
rx_status->flag |= RX_FLAG_HT;
- if (RSPEC_IS40MHZ(rspec))
+ if (rspec_is40mhz(rspec))
rx_status->flag |= RX_FLAG_40MHZ;
} else {
- switch (RSPEC2RATE(rspec)) {
+ switch (rspec2rate(rspec)) {
case BRCM_RATE_1M:
rx_status->rate_idx = 0;
break;
@@ -4618,10 +7833,10 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
/* Determine short preamble and rate_idx */
preamble = 0;
- if (IS_CCK(rspec)) {
+ if (is_cck_rate(rspec)) {
if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)
rx_status->flag |= RX_FLAG_SHORTPRE;
- } else if (IS_OFDM(rspec)) {
+ } else if (is_ofdm_rate(rspec)) {
rx_status->flag |= RX_FLAG_SHORTPRE;
} else {
wiphy_err(wlc->wiphy, "%s: Unknown modulation\n",
@@ -4629,7 +7844,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
}
}
- if (PLCP3_ISSGI(plcp[3]))
+ if (plcp3_issgi(plcp[3]))
rx_status->flag |= RX_FLAG_SHORT_GI;
if (rxh->RxStatus1 & RXS_DECERR) {
@@ -4661,102 +7876,6 @@ brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));
ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);
- return;
-}
-
-/* Process received frames */
-/*
- * Return true if more frames need to be processed. false otherwise.
- * Param 'bound' indicates max. # frames to process before break out.
- */
-void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
-{
- struct d11rxhdr *rxh;
- struct ieee80211_hdr *h;
- uint len;
- bool is_amsdu;
-
- BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
- /* frame starts with rxhdr */
- rxh = (struct d11rxhdr *) (p->data);
-
- /* strip off rxhdr */
- skb_pull(p, BRCMS_HWRXOFF);
-
- /* fixup rx header endianness */
- rxh->RxFrameSize = le16_to_cpu(rxh->RxFrameSize);
- rxh->PhyRxStatus_0 = le16_to_cpu(rxh->PhyRxStatus_0);
- rxh->PhyRxStatus_1 = le16_to_cpu(rxh->PhyRxStatus_1);
- rxh->PhyRxStatus_2 = le16_to_cpu(rxh->PhyRxStatus_2);
- rxh->PhyRxStatus_3 = le16_to_cpu(rxh->PhyRxStatus_3);
- rxh->PhyRxStatus_4 = le16_to_cpu(rxh->PhyRxStatus_4);
- rxh->PhyRxStatus_5 = le16_to_cpu(rxh->PhyRxStatus_5);
- rxh->RxStatus1 = le16_to_cpu(rxh->RxStatus1);
- rxh->RxStatus2 = le16_to_cpu(rxh->RxStatus2);
- rxh->RxTSFTime = le16_to_cpu(rxh->RxTSFTime);
- rxh->RxChan = le16_to_cpu(rxh->RxChan);
-
- /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
- if (rxh->RxStatus1 & RXS_PBPRES) {
- if (p->len < 2) {
- wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
- "len %d\n", wlc->pub->unit, p->len);
- goto toss;
- }
- skb_pull(p, 2);
- }
-
- h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
- len = p->len;
-
- if (rxh->RxStatus1 & RXS_FCSERR) {
- if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
- wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
- " tossing\n");
- goto toss;
- } else {
- wiphy_err(wlc->wiphy, "RCSERR!!!\n");
- goto toss;
- }
- }
-
- /* check received pkt has at least frame control field */
- if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control)) {
- goto toss;
- }
-
- is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
-
- /* explicitly test bad src address to avoid sending bad deauth */
- if (!is_amsdu) {
- /* CTS and ACK CTL frames are w/o a2 */
-
- if (ieee80211_is_data(h->frame_control) ||
- ieee80211_is_mgmt(h->frame_control)) {
- if ((is_zero_ether_addr(h->addr2) ||
- is_multicast_ether_addr(h->addr2))) {
- wiphy_err(wlc->wiphy, "wl%d: %s: dropping a "
- "frame with invalid src mac address,"
- " a2: %pM\n",
- wlc->pub->unit, __func__, h->addr2);
- goto toss;
- }
- }
- }
-
- /* due to sheer numbers, toss out probe reqs for now */
- if (ieee80211_is_probe_req(h->frame_control))
- goto toss;
-
- if (is_amsdu)
- goto toss;
-
- brcms_c_recvctl(wlc, rxh, p);
- return;
-
- toss:
- brcmu_pkt_buf_free_skb(p);
}
/* calculate frame duration for Mixed-mode L-SIG spoofing, return
@@ -4766,76 +7885,28 @@ void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
* len = 3(nsyms + nstream + 3) - 3
*/
u16
-brcms_c_calc_lsig_len(struct brcms_c_info *wlc, ratespec_t ratespec,
+brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
uint mac_len)
{
uint nsyms, len = 0, kNdps;
BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
- wlc->pub->unit, RSPEC2RATE(ratespec), mac_len);
-
- if (IS_MCS(ratespec)) {
- uint mcs = ratespec & RSPEC_RATE_MASK;
- /* MCS_TXS(mcs) returns num tx streams - 1 */
- int tot_streams = (MCS_TXS(mcs) + 1) + RSPEC_STC(ratespec);
-
- /* the payload duration calculation matches that of regular ofdm */
- /* 1000Ndbps = kbps * 4 */
- kNdps =
- MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
- RSPEC_ISSGI(ratespec)) * 4;
-
- if (RSPEC_STC(ratespec) == 0)
- /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
- nsyms =
- CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
- APHY_TAIL_NBITS) * 1000, kNdps);
- else
- /* STBC needs to have even number of symbols */
- nsyms =
- 2 *
- CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
- APHY_TAIL_NBITS) * 1000, 2 * kNdps);
-
- nsyms += (tot_streams + 3); /* (+3) account for HT-SIG(2) and HT-STF(1) */
- /* 3 bytes/symbol @ legacy 6Mbps rate */
- len = (3 * nsyms) - 3; /* (-3) excluding service bits and tail bits */
- }
+ wlc->pub->unit, rspec2rate(ratespec), mac_len);
- return (u16) len;
-}
-
-/* calculate frame duration of a given rate and length, return time in usec unit */
-uint
-brcms_c_calc_frame_time(struct brcms_c_info *wlc, ratespec_t ratespec,
- u8 preamble_type, uint mac_len)
-{
- uint nsyms, dur = 0, Ndps, kNdps;
- uint rate = RSPEC2RATE(ratespec);
-
- if (rate == 0) {
- wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
- wlc->pub->unit);
- rate = BRCM_RATE_1M;
- }
-
- BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
- wlc->pub->unit, ratespec, preamble_type, mac_len);
-
- if (IS_MCS(ratespec)) {
+ if (is_mcs_rate(ratespec)) {
uint mcs = ratespec & RSPEC_RATE_MASK;
- int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
+ int tot_streams = (mcs_2_txstreams(mcs) + 1) +
+ rspec_stc(ratespec);
- dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
- if (preamble_type == BRCMS_MM_PREAMBLE)
- dur += PREN_MM_EXT;
+ /*
+ * the payload duration calculation matches that
+ * of regular ofdm
+ */
/* 1000Ndbps = kbps * 4 */
- kNdps =
- MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
- RSPEC_ISSGI(ratespec)) * 4;
+ kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),
+ rspec_issgi(ratespec)) * 4;
- if (RSPEC_STC(ratespec) == 0)
- /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
+ if (rspec_stc(ratespec) == 0)
nsyms =
CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
APHY_TAIL_NBITS) * 1000, kNdps);
@@ -4846,398 +7917,62 @@ brcms_c_calc_frame_time(struct brcms_c_info *wlc, ratespec_t ratespec,
CEIL((APHY_SERVICE_NBITS + 8 * mac_len +
APHY_TAIL_NBITS) * 1000, 2 * kNdps);
- dur += APHY_SYMBOL_TIME * nsyms;
- if (BAND_2G(wlc->band->bandtype))
- dur += DOT11_OFDM_SIGNAL_EXTENSION;
- } else if (IS_OFDM(rate)) {
- dur = APHY_PREAMBLE_TIME;
- dur += APHY_SIGNAL_TIME;
- /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
- Ndps = rate * 2;
- /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */
- nsyms =
- CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),
- Ndps);
- dur += APHY_SYMBOL_TIME * nsyms;
- if (BAND_2G(wlc->band->bandtype))
- dur += DOT11_OFDM_SIGNAL_EXTENSION;
- } else {
- /* calc # bits * 2 so factor of 2 in rate (1/2 mbps) will divide out */
- mac_len = mac_len * 8 * 2;
- /* calc ceiling of bits/rate = microseconds of air time */
- dur = (mac_len + rate - 1) / rate;
- if (preamble_type & BRCMS_SHORT_PREAMBLE)
- dur += BPHY_PLCP_SHORT_TIME;
- else
- dur += BPHY_PLCP_TIME;
- }
- return dur;
-}
-
-/* The opposite of brcms_c_calc_frame_time */
-static uint
-brcms_c_calc_frame_len(struct brcms_c_info *wlc, ratespec_t ratespec,
- u8 preamble_type, uint dur)
-{
- uint nsyms, mac_len, Ndps, kNdps;
- uint rate = RSPEC2RATE(ratespec);
-
- BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
- wlc->pub->unit, ratespec, preamble_type, dur);
-
- if (IS_MCS(ratespec)) {
- uint mcs = ratespec & RSPEC_RATE_MASK;
- int tot_streams = MCS_TXS(mcs) + RSPEC_STC(ratespec);
- dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);
- /* payload calculation matches that of regular ofdm */
- if (BAND_2G(wlc->band->bandtype))
- dur -= DOT11_OFDM_SIGNAL_EXTENSION;
- /* kNdbps = kbps * 4 */
- kNdps =
- MCS_RATE(mcs, RSPEC_IS40MHZ(ratespec),
- RSPEC_ISSGI(ratespec)) * 4;
- nsyms = dur / APHY_SYMBOL_TIME;
- mac_len =
- ((nsyms * kNdps) -
- ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;
- } else if (IS_OFDM(ratespec)) {
- dur -= APHY_PREAMBLE_TIME;
- dur -= APHY_SIGNAL_TIME;
- /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */
- Ndps = rate * 2;
- nsyms = dur / APHY_SYMBOL_TIME;
- mac_len =
- ((nsyms * Ndps) -
- (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;
- } else {
- if (preamble_type & BRCMS_SHORT_PREAMBLE)
- dur -= BPHY_PLCP_SHORT_TIME;
- else
- dur -= BPHY_PLCP_TIME;
- mac_len = dur * rate;
- /* divide out factor of 2 in rate (1/2 mbps) */
- mac_len = mac_len / 8 / 2;
- }
- return mac_len;
-}
-
-static uint
-brcms_c_calc_ba_time(struct brcms_c_info *wlc, ratespec_t rspec,
- u8 preamble_type)
-{
- BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
- "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
- /* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than
- * or equal to the rate of the immediately previous frame in the FES
- */
- rspec = BRCMS_BASIC_RATE(wlc, rspec);
- /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */
- return brcms_c_calc_frame_time(wlc, rspec, preamble_type,
- (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +
- FCS_LEN));
-}
-
-static uint
-brcms_c_calc_ack_time(struct brcms_c_info *wlc, ratespec_t rspec,
- u8 preamble_type)
-{
- uint dur = 0;
-
- BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
- wlc->pub->unit, rspec, preamble_type);
- /* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that is less than
- * or equal to the rate of the immediately previous frame in the FES
- */
- rspec = BRCMS_BASIC_RATE(wlc, rspec);
- /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */
- dur =
- brcms_c_calc_frame_time(wlc, rspec, preamble_type,
- (DOT11_ACK_LEN + FCS_LEN));
- return dur;
-}
-
-static uint
-brcms_c_calc_cts_time(struct brcms_c_info *wlc, ratespec_t rspec,
- u8 preamble_type)
-{
- BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
- wlc->pub->unit, rspec, preamble_type);
- return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
-}
-
-/* derive wlc->band->basic_rate[] table from 'rateset' */
-void brcms_c_rate_lookup_init(struct brcms_c_info *wlc, wlc_rateset_t *rateset)
-{
- u8 rate;
- u8 mandatory;
- u8 cck_basic = 0;
- u8 ofdm_basic = 0;
- u8 *br = wlc->band->basic_rate;
- uint i;
-
- /* incoming rates are in 500kbps units as in 802.11 Supported Rates */
- memset(br, 0, BRCM_MAXRATE + 1);
-
- /* For each basic rate in the rates list, make an entry in the
- * best basic lookup.
- */
- for (i = 0; i < rateset->count; i++) {
- /* only make an entry for a basic rate */
- if (!(rateset->rates[i] & BRCMS_RATE_FLAG))
- continue;
-
- /* mask off basic bit */
- rate = (rateset->rates[i] & BRCMS_RATE_MASK);
-
- if (rate > BRCM_MAXRATE) {
- wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
- "invalid rate 0x%X in rate set\n",
- rateset->rates[i]);
- continue;
- }
-
- br[rate] = rate;
- }
-
- /* The rate lookup table now has non-zero entries for each
- * basic rate, equal to the basic rate: br[basicN] = basicN
- *
- * To look up the best basic rate corresponding to any
- * particular rate, code can use the basic_rate table
- * like this
- *
- * basic_rate = wlc->band->basic_rate[tx_rate]
- *
- * Make sure there is a best basic rate entry for
- * every rate by walking up the table from low rates
- * to high, filling in holes in the lookup table
- */
-
- for (i = 0; i < wlc->band->hw_rateset.count; i++) {
- rate = wlc->band->hw_rateset.rates[i];
-
- if (br[rate] != 0) {
- /* This rate is a basic rate.
- * Keep track of the best basic rate so far by
- * modulation type.
- */
- if (IS_OFDM(rate))
- ofdm_basic = rate;
- else
- cck_basic = rate;
-
- continue;
- }
-
- /* This rate is not a basic rate so figure out the
- * best basic rate less than this rate and fill in
- * the hole in the table
- */
-
- br[rate] = IS_OFDM(rate) ? ofdm_basic : cck_basic;
-
- if (br[rate] != 0)
- continue;
-
- if (IS_OFDM(rate)) {
- /* In 11g and 11a, the OFDM mandatory rates are 6, 12, and 24 Mbps */
- if (rate >= BRCM_RATE_24M)
- mandatory = BRCM_RATE_24M;
- else if (rate >= BRCM_RATE_12M)
- mandatory = BRCM_RATE_12M;
- else
- mandatory = BRCM_RATE_6M;
- } else {
- /* In 11b, all the CCK rates are mandatory 1 - 11 Mbps */
- mandatory = rate;
- }
-
- br[rate] = mandatory;
- }
-}
-
-static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,
- u8 basic_rate)
-{
- u8 phy_rate, index;
- u8 basic_phy_rate, basic_index;
- u16 dir_table, basic_table;
- u16 basic_ptr;
-
- /* Shared memory address for the table we are reading */
- dir_table = IS_OFDM(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;
-
- /* Shared memory address for the table we are writing */
- basic_table = IS_OFDM(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;
-
- /*
- * for a given rate, the LS-nibble of the PLCP SIGNAL field is
- * the index into the rate table.
- */
- phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
- basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;
- index = phy_rate & 0xf;
- basic_index = basic_phy_rate & 0xf;
-
- /* Find the SHM pointer to the ACK rate entry by looking in the
- * Direct-map Table
- */
- basic_ptr = brcms_c_read_shm(wlc, (dir_table + basic_index * 2));
-
- /* Update the SHM BSS-basic-rate-set mapping table with the pointer
- * to the correct basic rate for the given incoming rate
- */
- brcms_c_write_shm(wlc, (basic_table + index * 2), basic_ptr);
-}
-
-static const wlc_rateset_t *brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)
-{
- const wlc_rateset_t *rs_dflt;
-
- if (BRCMS_PHY_11N_CAP(wlc->band)) {
- if (BAND_5G(wlc->band->bandtype))
- rs_dflt = &ofdm_mimo_rates;
- else
- rs_dflt = &cck_ofdm_mimo_rates;
- } else if (wlc->band->gmode)
- rs_dflt = &cck_ofdm_rates;
- else
- rs_dflt = &cck_rates;
-
- return rs_dflt;
-}
-
-void brcms_c_set_ratetable(struct brcms_c_info *wlc)
-{
- const wlc_rateset_t *rs_dflt;
- wlc_rateset_t rs;
- u8 rate, basic_rate;
- uint i;
-
- rs_dflt = brcms_c_rateset_get_hwrs(wlc);
-
- brcms_c_rateset_copy(rs_dflt, &rs);
- brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
-
- /* walk the phy rate table and update SHM basic rate lookup table */
- for (i = 0; i < rs.count; i++) {
- rate = rs.rates[i] & BRCMS_RATE_MASK;
-
- /* for a given rate BRCMS_BASIC_RATE returns the rate at
- * which a response ACK/CTS should be sent.
+ /* (+3) account for HT-SIG(2) and HT-STF(1) */
+ nsyms += (tot_streams + 3);
+ /*
+ * 3 bytes/symbol @ legacy 6Mbps rate
+ * (-3) excluding service bits and tail bits
*/
- basic_rate = BRCMS_BASIC_RATE(wlc, rate);
- if (basic_rate == 0) {
- /* This should only happen if we are using a
- * restricted rateset.
- */
- basic_rate = rs.rates[0] & BRCMS_RATE_MASK;
- }
-
- brcms_c_write_rate_shm(wlc, rate, basic_rate);
- }
-}
-
-/*
- * Return true if the specified rate is supported by the specified band.
- * BRCM_BAND_AUTO indicates the current band.
- */
-bool brcms_c_valid_rate(struct brcms_c_info *wlc, ratespec_t rspec, int band,
- bool verbose)
-{
- wlc_rateset_t *hw_rateset;
- uint i;
-
- if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype)) {
- hw_rateset = &wlc->band->hw_rateset;
- } else if (NBANDS(wlc) > 1) {
- hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;
- } else {
- /* other band specified and we are a single band device */
- return false;
+ len = (3 * nsyms) - 3;
}
- /* check if this is a mimo rate */
- if (IS_MCS(rspec)) {
- if (!VALID_MCS((rspec & RSPEC_RATE_MASK)))
- goto error;
-
- return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));
- }
-
- for (i = 0; i < hw_rateset->count; i++)
- if (hw_rateset->rates[i] == RSPEC2RATE(rspec))
- return true;
- error:
- if (verbose) {
- wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
- "not in hw_rateset\n", wlc->pub->unit, rspec);
- }
-
- return false;
-}
-
-static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
-{
- uint i;
- struct brcms_band *band;
-
- for (i = 0; i < NBANDS(wlc); i++) {
- if (IS_SINGLEBAND_5G(wlc->deviceid))
- i = BAND_5G_INDEX;
- band = wlc->bandstate[i];
- if (band->bandtype == BRCM_BAND_5G) {
- if ((bwcap == BRCMS_N_BW_40ALL)
- || (bwcap == BRCMS_N_BW_20IN2G_40IN5G))
- band->mimo_cap_40 = true;
- else
- band->mimo_cap_40 = false;
- } else {
- if (bwcap == BRCMS_N_BW_40ALL)
- band->mimo_cap_40 = true;
- else
- band->mimo_cap_40 = false;
- }
- }
+ return (u16) len;
}
-void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
+static void
+brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
{
- const wlc_rateset_t *rs_dflt;
- wlc_rateset_t rs;
+ const struct brcms_c_rateset *rs_dflt;
+ struct brcms_c_rateset rs;
u8 rate;
u16 entry_ptr;
u8 plcp[D11_PHY_HDR_LEN];
u16 dur, sifs;
uint i;
- sifs = SIFS(wlc->band);
+ sifs = get_sifs(wlc->band);
rs_dflt = brcms_c_rateset_get_hwrs(wlc);
brcms_c_rateset_copy(rs_dflt, &rs);
brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);
- /* walk the phy rate table and update MAC core SHM basic rate table entries */
+ /*
+ * walk the phy rate table and update MAC core SHM
+ * basic rate table entries
+ */
for (i = 0; i < rs.count; i++) {
rate = rs.rates[i] & BRCMS_RATE_MASK;
- entry_ptr = brcms_c_rate_shm_offset(wlc, rate);
+ entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);
/* Calculate the Probe Response PLCP for the given rate */
brcms_c_compute_plcp(wlc, rate, frame_len, plcp);
- /* Calculate the duration of the Probe Response frame plus SIFS for the MAC */
+ /*
+ * Calculate the duration of the Probe Response
+ * frame plus SIFS for the MAC
+ */
dur = (u16) brcms_c_calc_frame_time(wlc, rate,
BRCMS_LONG_PREAMBLE, frame_len);
dur += sifs;
/* Update the SHM Rate Table entry Probe Response values */
- brcms_c_write_shm(wlc, entry_ptr + M_RT_PRS_PLCP_POS,
+ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,
(u16) (plcp[0] + (plcp[1] << 8)));
- brcms_c_write_shm(wlc, entry_ptr + M_RT_PRS_PLCP_POS + 2,
+ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,
(u16) (plcp[2] + (plcp[3] << 8)));
- brcms_c_write_shm(wlc, entry_ptr + M_RT_PRS_DUR_POS, dur);
+ brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);
}
}
@@ -5250,12 +7985,12 @@ void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)
*
* *len on input contains the max length of the packet available.
*
- * The *len value is set to the number of bytes in buf used, and starts with the PLCP
- * and included up to, but not including, the 4 byte FCS.
+ * The *len value is set to the number of bytes in buf used, and starts
+ * with the PLCP and included up to, but not including, the 4 byte FCS.
*/
static void
brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
- ratespec_t bcn_rspec,
+ u32 bcn_rspec,
struct brcms_bss_cfg *cfg, u16 *buf, int *len)
{
static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255};
@@ -5263,36 +7998,33 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
struct ieee80211_mgmt *h;
int hdr_len, body_len;
- if (MBSS_BCN_ENAB(cfg) && type == IEEE80211_STYPE_BEACON)
- hdr_len = DOT11_MAC_HDR_LEN;
- else
- hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
- body_len = *len - hdr_len; /* calc buffer size provided for frame body */
+ hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN;
- *len = hdr_len + body_len; /* return actual size */
+ /* calc buffer size provided for frame body */
+ body_len = *len - hdr_len;
+ /* return actual size */
+ *len = hdr_len + body_len;
/* format PHY and MAC headers */
memset((char *)buf, 0, hdr_len);
plcp = (struct cck_phy_hdr *) buf;
- /* PLCP for Probe Response frames are filled in from core's rate table */
- if (type == IEEE80211_STYPE_BEACON && !MBSS_BCN_ENAB(cfg)) {
+ /*
+ * PLCP for Probe Response frames are filled in from
+ * core's rate table
+ */
+ if (type == IEEE80211_STYPE_BEACON)
/* fill in PLCP */
brcms_c_compute_plcp(wlc, bcn_rspec,
(DOT11_MAC_HDR_LEN + body_len + FCS_LEN),
(u8 *) plcp);
- }
/* "Regular" and 16 MBSS but not for 4 MBSS */
/* Update the phytxctl for the beacon based on the rspec */
- if (!SOFTBCN_ENAB(cfg))
- brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
+ brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec);
- if (MBSS_BCN_ENAB(cfg) && type == IEEE80211_STYPE_BEACON)
- h = (struct ieee80211_mgmt *)&plcp[0];
- else
- h = (struct ieee80211_mgmt *)&plcp[1];
+ h = (struct ieee80211_mgmt *)&plcp[1];
/* fill in 802.11 header */
h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type);
@@ -5305,80 +8037,28 @@ brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type,
memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN);
/* SEQ filled in by MAC */
-
- return;
}
-int brcms_c_get_header_len()
+int brcms_c_get_header_len(void)
{
return TXOFF;
}
-/* Update a beacon for a particular BSS
- * For MBSS, this updates the software template and sets "latest" to the index of the
- * template updated.
- * Otherwise, it updates the hardware template.
- */
-void brcms_c_bss_update_beacon(struct brcms_c_info *wlc,
- struct brcms_bss_cfg *cfg)
-{
- int len = BCN_TMPL_LEN;
-
- /* Clear the soft intmask */
- wlc->defmacintmask &= ~MI_BCNTPL;
-
- if (!cfg->up) { /* Only allow updates on an UP bss */
- return;
- }
-
- /* Optimize: Some of if/else could be combined */
- if (!MBSS_BCN_ENAB(cfg) && HWBCN_ENAB(cfg)) {
- /* Hardware beaconing for this config */
- u16 bcn[BCN_TMPL_LEN / 2];
- u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
- d11regs_t *regs = wlc->regs;
-
- /* Check if both templates are in use, if so sched. an interrupt
- * that will call back into this routine
- */
- if ((R_REG(&regs->maccommand) & both_valid) == both_valid) {
- /* clear any previous status */
- W_REG(&regs->macintstatus, MI_BCNTPL);
- }
- /* Check that after scheduling the interrupt both of the
- * templates are still busy. if not clear the int. & remask
- */
- if ((R_REG(&regs->maccommand) & both_valid) == both_valid) {
- wlc->defmacintmask |= MI_BCNTPL;
- return;
- }
-
- wlc->bcn_rspec =
- brcms_c_lowest_basic_rspec(wlc, &cfg->current_bss->rateset);
- /* update the template and ucode shm */
- brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_BEACON,
- wlc->bcn_rspec, cfg, bcn, &len);
- brcms_c_write_hw_bcntemplates(wlc, bcn, len, false);
- }
-}
-
/*
* Update all beacons for the system.
*/
void brcms_c_update_beacon(struct brcms_c_info *wlc)
{
- int idx;
- struct brcms_bss_cfg *bsscfg;
+ struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
- /* update AP or IBSS beacons */
- FOREACH_BSS(wlc, idx, bsscfg) {
- if (bsscfg->up && (BSSCFG_AP(bsscfg) || !bsscfg->BSS))
- brcms_c_bss_update_beacon(wlc, bsscfg);
- }
+ if (bsscfg->up && !bsscfg->BSS)
+ /* Clear the soft intmask */
+ wlc->defmacintmask &= ~MI_BCNTPL;
}
/* Write ssid into shared memory */
-void brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
+static void
+brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
{
u8 *ssidptr = cfg->SSID;
u16 base = M_SSID;
@@ -5389,24 +8069,10 @@ void brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)
memcpy(ssidbuf, ssidptr, cfg->SSID_len);
brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);
-
- if (!MBSS_BCN_ENAB(cfg))
- brcms_c_write_shm(wlc, M_SSIDLEN, (u16) cfg->SSID_len);
-}
-
-void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
-{
- int idx;
- struct brcms_bss_cfg *bsscfg;
-
- /* update AP or IBSS probe responses */
- FOREACH_BSS(wlc, idx, bsscfg) {
- if (bsscfg->up && (BSSCFG_AP(bsscfg) || !bsscfg->BSS))
- brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
- }
+ brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);
}
-void
+static void
brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
struct brcms_bss_cfg *cfg,
bool suspend)
@@ -5414,40 +8080,48 @@ brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
u16 prb_resp[BCN_TMPL_LEN / 2];
int len = BCN_TMPL_LEN;
- /* write the probe response to hardware, or save in the config structure */
- if (!MBSS_PRB_ENAB(cfg)) {
+ /*
+ * write the probe response to hardware, or save in
+ * the config structure
+ */
+
+ /* create the probe response template */
+ brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
+ cfg, prb_resp, &len);
- /* create the probe response template */
- brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0,
- cfg, prb_resp, &len);
+ if (suspend)
+ brcms_c_suspend_mac_and_wait(wlc);
- if (suspend)
- brcms_c_suspend_mac_and_wait(wlc);
+ /* write the probe response into the template region */
+ brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
+ (len + 3) & ~3, prb_resp);
- /* write the probe response into the template region */
- brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,
- (len + 3) & ~3, prb_resp);
+ /* write the length of the probe response frame (+PLCP/-FCS) */
+ brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);
- /* write the length of the probe response frame (+PLCP/-FCS) */
- brcms_c_write_shm(wlc, M_PRB_RESP_FRM_LEN, (u16) len);
+ /* write the SSID and SSID length */
+ brcms_c_shm_ssid_upd(wlc, cfg);
- /* write the SSID and SSID length */
- brcms_c_shm_ssid_upd(wlc, cfg);
+ /*
+ * Write PLCP headers and durations for probe response frames
+ * at all rates. Use the actual frame length covered by the
+ * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()
+ * by subtracting the PLCP len and adding the FCS.
+ */
+ len += (-D11_PHY_HDR_LEN + FCS_LEN);
+ brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
- /*
- * Write PLCP headers and durations for probe response frames at all rates.
- * Use the actual frame length covered by the PLCP header for the call to
- * brcms_c_mod_prb_rsp_rate_table() by subtracting the PLCP len
- * and adding the FCS.
- */
- len += (-D11_PHY_HDR_LEN + FCS_LEN);
- brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len);
+ if (suspend)
+ brcms_c_enable_mac(wlc);
+}
- if (suspend)
- brcms_c_enable_mac(wlc);
- } else { /* Generating probe resp in sw; update local template */
- /* error: No software probe response support without MBSS */
- }
+void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
+{
+ struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
+
+ /* update AP or IBSS probe responses */
+ if (bsscfg->up && !bsscfg->BSS)
+ brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
}
/* prepares pdu for transmission. returns BCM error codes */
@@ -5470,641 +8144,632 @@ int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
*fifop = fifo;
/* return if insufficient dma resources */
- if (TXAVAIL(wlc, fifo) < MAX_DMA_SEGS) {
+ if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
/* Mark precedences related to this FIFO, unsendable */
- BRCMS_TX_FIFO_CLEAR(wlc, fifo);
+ /* A fifo is full. Clear precedences related to that FIFO */
+ wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
return -EBUSY;
}
return 0;
}
-/* init tx reported rate mechanism */
-void brcms_c_reprate_init(struct brcms_c_info *wlc)
+int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
+ uint *blocks)
{
- int i;
- struct brcms_bss_cfg *bsscfg;
+ if (fifo >= NFIFO)
+ return -EINVAL;
- FOREACH_BSS(wlc, i, bsscfg) {
- brcms_c_bsscfg_reprate_init(bsscfg);
- }
-}
+ *blocks = wlc_hw->xmtfifo_sz[fifo];
-/* per bsscfg init tx reported rate mechanism */
-void brcms_c_bsscfg_reprate_init(struct brcms_bss_cfg *bsscfg)
-{
- bsscfg->txrspecidx = 0;
- memset((char *)bsscfg->txrspec, 0, sizeof(bsscfg->txrspec));
+ return 0;
}
-void brcms_default_rateset(struct brcms_c_info *wlc, wlc_rateset_t *rs)
+void
+brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
+ const u8 *addr)
{
- brcms_c_rateset_default(rs, NULL, wlc->band->phytype,
- wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,
- (bool) N_ENAB(wlc->pub),
- CHSPEC_WLC_BW(wlc->default_bss->chanspec),
- wlc->stf->txstreams);
+ brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
+ if (match_reg_offset == RCM_BSSID_OFFSET)
+ memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);
}
-static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
+/*
+ * Flag 'scan in progress' to withhold dynamic phy calibration
+ */
+void brcms_c_scan_start(struct brcms_c_info *wlc)
{
- chanspec_t chanspec;
- struct brcms_band *band;
- struct brcms_bss_info *bi = wlc->default_bss;
-
- /* init default and target BSS with some sane initial values */
- memset((char *)(bi), 0, sizeof(struct brcms_bss_info));
- bi->beacon_period = BEACON_INTERVAL_DEFAULT;
- bi->dtim_period = DTIM_INTERVAL_DEFAULT;
-
- /* fill the default channel as the first valid channel
- * starting from the 2G channels
- */
- chanspec = CH20MHZ_CHSPEC(1);
- wlc->home_chanspec = bi->chanspec = chanspec;
-
- /* find the band of our default channel */
- band = wlc->band;
- if (NBANDS(wlc) > 1 && band->bandunit != CHSPEC_BANDUNIT(chanspec))
- band = wlc->bandstate[OTHERBANDUNIT(wlc)];
-
- /* init bss rates to the band specific default rate set */
- brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,
- band->bandtype, false, BRCMS_RATE_MASK_FULL,
- (bool) N_ENAB(wlc->pub), CHSPEC_WLC_BW(chanspec),
- wlc->stf->txstreams);
-
- if (N_ENAB(wlc->pub))
- bi->flags |= BRCMS_BSS_HT;
+ wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
}
-static ratespec_t
-mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
- u32 int_val)
+void brcms_c_scan_stop(struct brcms_c_info *wlc)
{
- u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
- u8 rate = int_val & NRATE_RATE_MASK;
- ratespec_t rspec;
- bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);
- bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);
- bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)
- == NRATE_OVERRIDE_MCS_ONLY);
- int bcmerror = 0;
-
- if (!ismcs) {
- return (ratespec_t) rate;
- }
-
- /* validate the combination of rate/mcs/stf is allowed */
- if (N_ENAB(wlc->pub) && ismcs) {
- /* mcs only allowed when nmode */
- if (stf > PHY_TXC1_MODE_SDM) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
- BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
-
- /* mcs 32 is a special case, DUP mode 40 only */
- if (rate == 32) {
- if (!CHSPEC_IS40(wlc->home_chanspec) ||
- ((stf != PHY_TXC1_MODE_SISO)
- && (stf != PHY_TXC1_MODE_CDD))) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
- "32\n", BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
- /* mcs > 7 must use stf SDM */
- } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
- /* mcs > 7 must use stf SDM */
- if (stf != PHY_TXC1_MODE_SDM) {
- BCMMSG(wlc->wiphy, "wl%d: enabling "
- "SDM mode for mcs %d\n",
- BRCMS_UNIT(wlc), rate);
- stf = PHY_TXC1_MODE_SDM;
- }
- } else {
- /* MCS 0-7 may use SISO, CDD, and for phy_rev >= 3 STBC */
- if ((stf > PHY_TXC1_MODE_STBC) ||
- (!BRCMS_STBC_CAP_PHY(wlc)
- && (stf == PHY_TXC1_MODE_STBC))) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
- "\n", BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
- }
- } else if (IS_OFDM(rate)) {
- if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
- BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
- } else if (IS_CCK(rate)) {
- if ((cur_band->bandtype != BRCM_BAND_2G)
- || (stf != PHY_TXC1_MODE_SISO)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
- BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
- } else {
- wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
- BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
- /* make sure multiple antennae are available for non-siso rates */
- if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
- wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
- "request\n", BRCMS_UNIT(wlc), __func__);
- bcmerror = -EINVAL;
- goto done;
- }
-
- rspec = rate;
- if (ismcs) {
- rspec |= RSPEC_MIMORATE;
- /* For STBC populate the STC field of the ratespec */
- if (stf == PHY_TXC1_MODE_STBC) {
- u8 stc;
- stc = 1; /* Nss for single stream is always 1 */
- rspec |= (stc << RSPEC_STC_SHIFT);
- }
- }
-
- rspec |= (stf << RSPEC_STF_SHIFT);
-
- if (override_mcs_only)
- rspec |= RSPEC_OVERRIDE_MCS_ONLY;
-
- if (issgi)
- rspec |= RSPEC_SHORT_GI;
-
- if ((rate != 0)
- && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true)) {
- return rate;
- }
-
- return rspec;
-done:
- return rate;
+ wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
}
-/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */
-static int
-brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
- bool writeToShm)
+void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
{
- int idle_busy_ratio_x_16 = 0;
- uint offset =
- isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
- M_TX_IDLE_BUSY_RATIO_X_16_CCK;
- if (duty_cycle > 100 || duty_cycle < 0) {
- wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n",
- wlc->pub->unit);
- return -EINVAL;
- }
- if (duty_cycle)
- idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;
- /* Only write to shared memory when wl is up */
- if (writeToShm)
- brcms_c_write_shm(wlc, offset, (u16) idle_busy_ratio_x_16);
-
- if (isOFDM)
- wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;
- else
- wlc->tx_duty_cycle_cck = (u16) duty_cycle;
-
- return 0;
+ wlc->pub->associated = state;
+ wlc->bsscfg->associated = state;
}
-/* Read a single u16 from shared memory.
- * SHM 'offset' needs to be an even address
+/*
+ * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
+ * AMPDU traffic, packets pending in hardware have to be invalidated so that
+ * when later on hardware releases them, they can be handled appropriately.
*/
-u16 brcms_c_read_shm(struct brcms_c_info *wlc, uint offset)
+void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
+ struct ieee80211_sta *sta,
+ void (*dma_callback_fn))
{
- return brcms_b_read_shm(wlc->hw, offset);
+ struct dma_pub *dmah;
+ int i;
+ for (i = 0; i < NFIFO; i++) {
+ dmah = hw->di[i];
+ if (dmah != NULL)
+ dma_walk_packets(dmah, dma_callback_fn, sta);
+ }
}
-/* Write a single u16 to shared memory.
- * SHM 'offset' needs to be an even address
- */
-void brcms_c_write_shm(struct brcms_c_info *wlc, uint offset, u16 v)
+int brcms_c_get_curband(struct brcms_c_info *wlc)
{
- brcms_b_write_shm(wlc->hw, offset, v);
+ return wlc->band->bandunit;
}
-/* Copy a buffer to shared memory.
- * SHM 'offset' needs to be an even address and
- * Buffer length 'len' must be an even number of bytes
- */
-void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset, const void *buf,
- int len)
+void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
{
- /* offset and len need to be even */
- if (len <= 0 || (offset & 1) || (len & 1))
- return;
-
- brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);
+ /* flush packet queue when requested */
+ if (drop)
+ brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
+ /* wait for queue and DMA fifos to run dry */
+ while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0)
+ brcms_msleep(wlc->wl, 1);
}
-/* wrapper BMAC functions to for HIGH driver access */
-void brcms_c_mctrl(struct brcms_c_info *wlc, u32 mask, u32 val)
+void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)
{
- brcms_b_mctrl(wlc->hw, mask, val);
+ wlc->bcn_li_bcn = interval;
+ if (wlc->pub->up)
+ brcms_c_bcn_li_upd(wlc);
}
-void brcms_c_mhf(struct brcms_c_info *wlc, u8 idx, u16 mask, u16 val, int bands)
+int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)
{
- brcms_b_mhf(wlc->hw, idx, mask, val, bands);
-}
+ uint qdbm;
-int brcms_c_xmtfifo_sz_get(struct brcms_c_info *wlc, uint fifo, uint *blocks)
-{
- return brcms_b_xmtfifo_sz_get(wlc->hw, fifo, blocks);
+ /* Remove override bit and clip to max qdbm value */
+ qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);
+ return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);
}
-void brcms_c_write_template_ram(struct brcms_c_info *wlc, int offset, int len,
- void *buf)
+int brcms_c_get_tx_power(struct brcms_c_info *wlc)
{
- brcms_b_write_template_ram(wlc->hw, offset, len, buf);
-}
+ uint qdbm;
+ bool override;
-void brcms_c_write_hw_bcntemplates(struct brcms_c_info *wlc, void *bcn, int len,
- bool both)
-{
- brcms_b_write_hw_bcntemplates(wlc->hw, bcn, len, both);
-}
+ wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);
-void
-brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,
- const u8 *addr)
-{
- brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);
- if (match_reg_offset == RCM_BSSID_OFFSET)
- memcpy(wlc->cfg->BSSID, addr, ETH_ALEN);
+ /* Return qdbm units */
+ return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
}
-void brcms_c_pllreq(struct brcms_c_info *wlc, bool set, mbool req_bit)
+void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
{
- brcms_b_pllreq(wlc->hw, set, req_bit);
+ wlc->mpc = mpc;
+ brcms_c_radio_mpc_upd(wlc);
}
-void brcms_c_reset_bmac_done(struct brcms_c_info *wlc)
+/* Process received frames */
+/*
+ * Return true if more frames need to be processed. false otherwise.
+ * Param 'bound' indicates max. # frames to process before break out.
+ */
+static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
{
-}
+ struct d11rxhdr *rxh;
+ struct ieee80211_hdr *h;
+ uint len;
+ bool is_amsdu;
-/* check for the particular priority flow control bit being set */
-bool
-brcms_c_txflowcontrol_prio_isset(struct brcms_c_info *wlc,
- struct brcms_txq_info *q,
- int prio)
-{
- uint prio_mask;
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
- if (prio == ALLPRIO) {
- prio_mask = TXQ_STOP_FOR_PRIOFC_MASK;
- } else {
- prio_mask = NBITVAL(prio);
- }
+ /* frame starts with rxhdr */
+ rxh = (struct d11rxhdr *) (p->data);
- return (q->stopped & prio_mask) == prio_mask;
-}
+ /* strip off rxhdr */
+ skb_pull(p, BRCMS_HWRXOFF);
-/* propagate the flow control to all interfaces using the given tx queue */
-void brcms_c_txflowcontrol(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi,
- bool on, int prio)
-{
- uint prio_bits;
- uint cur_bits;
+ /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
+ if (rxh->RxStatus1 & RXS_PBPRES) {
+ if (p->len < 2) {
+ wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
+ "len %d\n", wlc->pub->unit, p->len);
+ goto toss;
+ }
+ skb_pull(p, 2);
+ }
- BCMMSG(wlc->wiphy, "flow control kicks in\n");
+ h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);
+ len = p->len;
- if (prio == ALLPRIO) {
- prio_bits = TXQ_STOP_FOR_PRIOFC_MASK;
- } else {
- prio_bits = NBITVAL(prio);
+ if (rxh->RxStatus1 & RXS_FCSERR) {
+ if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) {
+ wiphy_err(wlc->wiphy, "FCSERR while scanning******* -"
+ " tossing\n");
+ goto toss;
+ } else {
+ wiphy_err(wlc->wiphy, "RCSERR!!!\n");
+ goto toss;
+ }
}
- cur_bits = qi->stopped & prio_bits;
+ /* check received pkt has at least frame control field */
+ if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))
+ goto toss;
- /* Check for the case of no change and return early
- * Otherwise update the bit and continue
- */
- if (on) {
- if (cur_bits == prio_bits) {
- return;
- }
- mboolset(qi->stopped, prio_bits);
- } else {
- if (cur_bits == 0) {
- return;
+ /* not supporting A-MSDU */
+ is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;
+ if (is_amsdu)
+ goto toss;
+
+ brcms_c_recvctl(wlc, rxh, p);
+ return;
+
+ toss:
+ brcmu_pkt_buf_free_skb(p);
+}
+
+/* Process received frames */
+/*
+ * Return true if more frames need to be processed. false otherwise.
+ * Param 'bound' indicates max. # frames to process before break out.
+ */
+static bool
+brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
+{
+ struct sk_buff *p;
+ struct sk_buff *head = NULL;
+ struct sk_buff *tail = NULL;
+ uint n = 0;
+ uint bound_limit = bound ? RXBND : -1;
+
+ BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+ /* gather received frames */
+ while ((p = dma_rx(wlc_hw->di[fifo]))) {
+
+ if (!tail)
+ head = tail = p;
+ else {
+ tail->prev = p;
+ tail = p;
}
- mboolclr(qi->stopped, prio_bits);
+
+ /* !give others some time to run! */
+ if (++n >= bound_limit)
+ break;
}
- /* If there is a flow control override we will not change the external
- * flow control state.
- */
- if (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK) {
- return;
+ /* post more rbufs */
+ dma_rxfill(wlc_hw->di[fifo]);
+
+ /* process each frame */
+ while ((p = head) != NULL) {
+ struct d11rxhdr_le *rxh_le;
+ struct d11rxhdr *rxh;
+ head = head->prev;
+ p->prev = NULL;
+
+ rxh_le = (struct d11rxhdr_le *)p->data;
+ rxh = (struct d11rxhdr *)p->data;
+
+ /* fixup rx header endianness */
+ rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);
+ rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);
+ rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);
+ rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);
+ rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);
+ rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);
+ rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);
+ rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);
+ rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);
+ rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);
+ rxh->RxChan = le16_to_cpu(rxh_le->RxChan);
+
+ brcms_c_recv(wlc_hw->wlc, p);
}
- brcms_c_txflowcontrol_signal(wlc, qi, on, prio);
+ return n >= bound_limit;
}
-void
-brcms_c_txflowcontrol_override(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi,
- bool on, uint override)
+/* second-level interrupt processing
+ * Return true if another dpc needs to be re-scheduled. false otherwise.
+ * Param 'bounded' indicates if applicable loops should be bounded.
+ */
+bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
{
- uint prev_override;
+ u32 macintstatus;
+ struct brcms_hardware *wlc_hw = wlc->hw;
+ struct d11regs __iomem *regs = wlc_hw->regs;
+ struct wiphy *wiphy = wlc->wiphy;
- prev_override = (qi->stopped & ~TXQ_STOP_FOR_PRIOFC_MASK);
+ if (brcms_deviceremoved(wlc)) {
+ wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+ __func__);
+ brcms_down(wlc->wl);
+ return false;
+ }
- /* Update the flow control bits and do an early return if there is
- * no change in the external flow control state.
- */
- if (on) {
- mboolset(qi->stopped, override);
- /* if there was a previous override bit on, then setting this
- * makes no difference.
- */
- if (prev_override) {
- return;
- }
+ /* grab and clear the saved software intstatus bits */
+ macintstatus = wlc->macintstatus;
+ wlc->macintstatus = 0;
- brcms_c_txflowcontrol_signal(wlc, qi, ON, ALLPRIO);
- } else {
- mboolclr(qi->stopped, override);
- /* clearing an override bit will only make a difference for
- * flow control if it was the only bit set. For any other
- * override setting, just return
- */
- if (prev_override != override) {
- return;
- }
+ BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
+ wlc_hw->unit, macintstatus);
- if (qi->stopped == 0) {
- brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
- } else {
- int prio;
+ WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
- for (prio = MAXPRIO; prio >= 0; prio--) {
- if (!mboolisset(qi->stopped, NBITVAL(prio)))
- brcms_c_txflowcontrol_signal(
- wlc, qi, OFF, prio);
- }
+ /* tx status */
+ if (macintstatus & MI_TFS) {
+ bool fatal;
+ if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
+ wlc->macintstatus |= MI_TFS;
+ if (fatal) {
+ wiphy_err(wiphy, "MI_TFS: fatal\n");
+ goto fatal;
}
}
-}
-static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
-{
- struct brcms_txq_info *qi;
+ if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))
+ brcms_c_tbtt(wlc);
- for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
- if (qi->stopped) {
- brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
- qi->stopped = 0;
- }
+ /* ATIM window end */
+ if (macintstatus & MI_ATIMWINEND) {
+ BCMMSG(wlc->wiphy, "end of ATIM window\n");
+ OR_REG(&regs->maccommand, wlc->qvalid);
+ wlc->qvalid = 0;
}
-}
-static void
-brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi, bool on, int prio)
-{
-#ifdef NON_FUNCTIONAL
- /* wlcif_list is never filled so this function is not functional */
- struct brcms_c_if *wlcif;
+ /*
+ * received data or control frame, MI_DMAINT is
+ * indication of RX_FIFO interrupt
+ */
+ if (macintstatus & MI_DMAINT)
+ if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))
+ wlc->macintstatus |= MI_DMAINT;
- for (wlcif = wlc->wlcif_list; wlcif != NULL; wlcif = wlcif->next) {
- if (wlcif->qi == qi && wlcif->flags & BRCMS_IF_LINKED)
- brcms_txflowcontrol(wlc->wl, wlcif->wlif, on, prio);
+ /* noise sample collected */
+ if (macintstatus & MI_BG_NOISE)
+ wlc_phy_noise_sample_intr(wlc_hw->band->pi);
+
+ if (macintstatus & MI_GP0) {
+ wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
+ "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
+
+ printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
+ __func__, wlc_hw->sih->chip,
+ wlc_hw->sih->chiprev);
+ /* big hammer */
+ brcms_init(wlc->wl);
}
-#endif
+
+ /* gptimer timeout */
+ if (macintstatus & MI_TO)
+ W_REG(&regs->gptimer, 0);
+
+ if (macintstatus & MI_RFDISABLE) {
+ BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
+ " RF Disable Input\n", wlc_hw->unit);
+ brcms_rfkill_set_hw_state(wlc->wl);
+ }
+
+ /* send any enq'd tx packets. Just makes sure to jump start tx */
+ if (!pktq_empty(&wlc->pkt_queue->q))
+ brcms_c_send_q(wlc);
+
+ /* it isn't done and needs to be resched if macintstatus is non-zero */
+ return wlc->macintstatus != 0;
+
+ fatal:
+ brcms_init(wlc->wl);
+ return wlc->macintstatus != 0;
}
-static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
+void brcms_c_init(struct brcms_c_info *wlc)
{
- struct brcms_txq_info *qi, *p;
+ struct d11regs __iomem *regs;
+ u16 chanspec;
+ bool mute = false;
- qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
- if (qi != NULL) {
+ BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+
+ regs = wlc->regs;
+
+ /*
+ * This will happen if a big-hammer was executed. In
+ * that case, we want to go back to the channel that
+ * we were on and not new channel
+ */
+ if (wlc->pub->associated)
+ chanspec = wlc->home_chanspec;
+ else
+ chanspec = brcms_c_init_chanspec(wlc);
+
+ brcms_b_init(wlc->hw, chanspec, mute);
+
+ /* update beacon listen interval */
+ brcms_c_bcn_li_upd(wlc);
+
+ /* write ethernet address to core */
+ brcms_c_set_mac(wlc->bsscfg);
+ brcms_c_set_bssid(wlc->bsscfg);
+
+ /* Update tsf_cfprep if associated and up */
+ if (wlc->pub->associated && wlc->bsscfg->up) {
+ u32 bi;
+
+ /* get beacon period and convert to uS */
+ bi = wlc->bsscfg->current_bss->beacon_period << 10;
/*
- * Have enough room for control packets along with HI watermark
- * Also, add room to txq for total psq packets if all the SCBs
- * leave PS mode. The watermark for flowcontrol to OS packets
- * will remain the same
+ * update since init path would reset
+ * to default value
*/
- brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
- (2 * wlc->pub->tunables->datahiwat) + PKTQ_LEN_DEFAULT
- + wlc->pub->psq_pkts_total);
+ W_REG(&regs->tsf_cfprep,
+ (bi << CFPREP_CBI_SHIFT));
- /* add this queue to the the global list */
- p = wlc->tx_queues;
- if (p == NULL) {
- wlc->tx_queues = qi;
- } else {
- while (p->next != NULL)
- p = p->next;
- p->next = qi;
- }
+ /* Update maccontrol PM related bits */
+ brcms_c_set_ps_ctrl(wlc);
}
- return qi;
-}
-static void brcms_c_txq_free(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi)
-{
- struct brcms_txq_info *p;
+ brcms_c_bandinit_ordered(wlc, chanspec);
- if (qi == NULL)
- return;
+ /* init probe response timeout */
+ brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);
- /* remove the queue from the linked list */
- p = wlc->tx_queues;
- if (p == qi)
- wlc->tx_queues = p->next;
- else {
- while (p != NULL && p->next != qi)
- p = p->next;
- if (p != NULL)
- p->next = p->next->next;
+ /* init max burst txop (framebursting) */
+ brcms_b_write_shm(wlc->hw, M_MBURST_TXOP,
+ (wlc->
+ _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));
+
+ /* initialize maximum allowed duty cycle */
+ brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);
+ brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);
+
+ /*
+ * Update some shared memory locations related to
+ * max AMPDU size allowed to received
+ */
+ brcms_c_ampdu_shm_upd(wlc->ampdu);
+
+ /* band-specific inits */
+ brcms_c_bsinit(wlc);
+
+ /* Enable EDCF mode (while the MAC is suspended) */
+ OR_REG(&regs->ifs_ctl, IFS_USEEDCF);
+ brcms_c_edcf_setparams(wlc, false);
+
+ /* Init precedence maps for empty FIFOs */
+ brcms_c_tx_prec_map_init(wlc);
+
+ /* read the ucode version if we have not yet done so */
+ if (wlc->ucode_rev == 0) {
+ wlc->ucode_rev =
+ brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16);
+ wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);
}
- kfree(qi);
-}
+ /* ..now really unleash hell (allow the MAC out of suspend) */
+ brcms_c_enable_mac(wlc);
-/*
- * Flag 'scan in progress' to withhold dynamic phy calibration
- */
-void brcms_c_scan_start(struct brcms_c_info *wlc)
-{
- wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);
-}
+ /* clear tx flow control */
+ brcms_c_txflowcontrol_reset(wlc);
-void brcms_c_scan_stop(struct brcms_c_info *wlc)
-{
- wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);
-}
+ /* enable the RF Disable Delay timer */
+ W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
-void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)
-{
- wlc->pub->associated = state;
- wlc->cfg->associated = state;
+ /* initialize mpc delay */
+ wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
+
+ /*
+ * Initialize WME parameters; if they haven't been set by some other
+ * mechanism (IOVar, etc) then read them from the hardware.
+ */
+ if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {
+ /* Uninitialized; read from HW */
+ int ac;
+
+ for (ac = 0; ac < AC_COUNT; ac++)
+ wlc->wme_retries[ac] =
+ brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
+ }
}
/*
- * When a remote STA/AP is removed by Mac80211, or when it can no longer accept
- * AMPDU traffic, packets pending in hardware have to be invalidated so that
- * when later on hardware releases them, they can be handled appropriately.
+ * The common driver entry routine. Error codes should be unique
*/
-void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
- struct ieee80211_sta *sta,
- void (*dma_callback_fn))
+struct brcms_c_info *
+brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
+ bool piomode, void __iomem *regsva, struct pci_dev *btparam,
+ uint *perr)
{
- struct dma_pub *dmah;
- int i;
- for (i = 0; i < NFIFO; i++) {
- dmah = hw->di[i];
- if (dmah != NULL)
- dma_walk_packets(dmah, dma_callback_fn, sta);
- }
-}
+ struct brcms_c_info *wlc;
+ uint err = 0;
+ uint i, j;
+ struct brcms_pub *pub;
-int brcms_c_get_curband(struct brcms_c_info *wlc)
-{
- return wlc->band->bandunit;
-}
+ /* allocate struct brcms_c_info state and its substructures */
+ wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device);
+ if (wlc == NULL)
+ goto fail;
+ wlc->wiphy = wl->wiphy;
+ pub = wlc->pub;
-void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
-{
- /* flush packet queue when requested */
- if (drop)
- brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
+#if defined(BCMDBG)
+ wlc_info_dbg = wlc;
+#endif
- /* wait for queue and DMA fifos to run dry */
- while (!pktq_empty(&wlc->pkt_queue->q) ||
- TXPKTPENDTOT(wlc) > 0) {
- brcms_msleep(wlc->wl, 1);
- }
-}
+ wlc->band = wlc->bandstate[0];
+ wlc->core = wlc->corestate;
+ wlc->wl = wl;
+ pub->unit = unit;
+ pub->_piomode = piomode;
+ wlc->bandinit_pending = false;
-int brcms_c_set_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int int_val)
-{
- int err = 0;
+ /* populate struct brcms_c_info with default values */
+ brcms_c_info_init(wlc, unit);
- switch (par_id) {
- case IOV_BCN_LI_BCN:
- wlc->bcn_li_bcn = (u8) int_val;
- if (wlc->pub->up)
- brcms_c_bcn_li_upd(wlc);
- break;
- /* As long as override is false, this only sets the *user*
- targets. User can twiddle this all he wants with no harm.
- wlc_phy_txpower_set() explicitly sets override to false if
- not internal or test.
- */
- case IOV_QTXPOWER:{
- u8 qdbm;
- bool override;
-
- /* Remove override bit and clip to max qdbm value */
- qdbm = (u8)min_t(u32, (int_val & ~WL_TXPWR_OVERRIDE), 0xff);
- /* Extract override setting */
- override = (int_val & WL_TXPWR_OVERRIDE) ? true : false;
- err =
- wlc_phy_txpower_set(wlc->band->pi, qdbm, override);
- break;
+ /* update sta/ap related parameters */
+ brcms_c_ap_upd(wlc);
+
+ /*
+ * low level attach steps(all hw accesses go
+ * inside, no more in rest of the attach)
+ */
+ err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva,
+ btparam);
+ if (err)
+ goto fail;
+
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);
+
+ pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);
+
+ /* disable allowed duty cycle */
+ wlc->tx_duty_cycle_ofdm = 0;
+ wlc->tx_duty_cycle_cck = 0;
+
+ brcms_c_stf_phy_chain_calc(wlc);
+
+ /* txchain 1: txant 0, txchain 2: txant 1 */
+ if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))
+ wlc->stf->txant = wlc->stf->hw_txchain - 1;
+
+ /* push to BMAC driver */
+ wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,
+ wlc->stf->hw_rxchain);
+
+ /* pull up some info resulting from the low attach */
+ for (i = 0; i < NFIFO; i++)
+ wlc->core->txavail[i] = wlc->hw->txavail[i];
+
+ memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
+ memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);
+
+ for (j = 0; j < wlc->pub->_nbands; j++) {
+ wlc->band = wlc->bandstate[j];
+
+ if (!brcms_c_attach_stf_ant_init(wlc)) {
+ err = 24;
+ goto fail;
}
- case IOV_MPC:
- wlc->mpc = (bool)int_val;
- brcms_c_radio_mpc_upd(wlc);
- break;
- default:
- err = -ENOTSUPP;
- }
- return err;
-}
-int brcms_c_get_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int *ret_int_ptr)
-{
- int err = 0;
+ /* default contention windows size limits */
+ wlc->band->CWmin = APHY_CWMIN;
+ wlc->band->CWmax = PHY_CWMAX;
- switch (par_id) {
- case IOV_BCN_LI_BCN:
- *ret_int_ptr = wlc->bcn_li_bcn;
- break;
- case IOV_QTXPOWER: {
- uint qdbm;
- bool override;
-
- err = wlc_phy_txpower_get(wlc->band->pi, &qdbm,
- &override);
- if (err != 0)
- return err;
-
- /* Return qdbm units */
- *ret_int_ptr =
- qdbm | (override ? WL_TXPWR_OVERRIDE : 0);
- break;
+ /* init gmode value */
+ if (wlc->band->bandtype == BRCM_BAND_2G) {
+ wlc->band->gmode = GMODE_AUTO;
+ brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,
+ wlc->band->gmode);
}
- case IOV_MPC:
- *ret_int_ptr = (s32) wlc->mpc;
- break;
- default:
- err = -ENOTSUPP;
+
+ /* init _n_enab supported mode */
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ pub->_n_enab = SUPPORT_11N;
+ brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,
+ ((pub->_n_enab ==
+ SUPPORT_11N) ? WL_11N_2x2 :
+ WL_11N_3x3));
+ }
+
+ /* init per-band default rateset, depend on band->gmode */
+ brcms_default_rateset(wlc, &wlc->band->defrateset);
+
+ /* fill in hw_rateset */
+ brcms_c_rateset_filter(&wlc->band->defrateset,
+ &wlc->band->hw_rateset, false,
+ BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,
+ (bool) (wlc->pub->_n_enab & SUPPORT_11N));
}
- return err;
-}
-/*
- * Search the name=value vars for a specific one and return its value.
- * Returns NULL if not found.
- */
-char *getvar(char *vars, const char *name)
-{
- char *s;
- int len;
+ /*
+ * update antenna config due to
+ * wlc->stf->txant/txchain/ant_rx_ovr change
+ */
+ brcms_c_stf_phy_txant_upd(wlc);
- if (!name)
- return NULL;
+ /* attach each modules */
+ err = brcms_c_attach_module(wlc);
+ if (err != 0)
+ goto fail;
- len = strlen(name);
- if (len == 0)
- return NULL;
+ if (!brcms_c_timers_init(wlc, unit)) {
+ wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,
+ __func__);
+ err = 32;
+ goto fail;
+ }
- /* first look in vars[] */
- for (s = vars; s && *s;) {
- if ((memcmp(s, name, len) == 0) && (s[len] == '='))
- return &s[len + 1];
+ /* depend on rateset, gmode */
+ wlc->cmi = brcms_c_channel_mgr_attach(wlc);
+ if (!wlc->cmi) {
+ wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"
+ "\n", unit, __func__);
+ err = 33;
+ goto fail;
+ }
- while (*s++)
- ;
+ /* init default when all parameters are ready, i.e. ->rateset */
+ brcms_c_bss_default_init(wlc);
+
+ /*
+ * Complete the wlc default state initializations..
+ */
+
+ /* allocate our initial queue */
+ wlc->pkt_queue = brcms_c_txq_alloc(wlc);
+ if (wlc->pkt_queue == NULL) {
+ wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
+ unit, __func__);
+ err = 100;
+ goto fail;
}
- /* nothing found */
- return NULL;
-}
-/*
- * Search the vars for a specific one and return its value as
- * an integer. Returns 0 if not found.
- */
-int getintvar(char *vars, const char *name)
-{
- char *val;
+ wlc->bsscfg->wlc = wlc;
- val = getvar(vars, name);
- if (val == NULL)
- return 0;
+ wlc->mimoft = FT_HT;
+ wlc->mimo_40txbw = AUTO;
+ wlc->ofdm_40txbw = AUTO;
+ wlc->cck_40txbw = AUTO;
+ brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);
+
+ /* Set default values of SGI */
+ if (BRCMS_SGI_CAP_PHY(wlc)) {
+ brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
+ BRCMS_N_SGI_40));
+ } else if (BRCMS_ISSSLPNPHY(wlc->band)) {
+ brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |
+ BRCMS_N_SGI_40));
+ } else {
+ brcms_c_ht_update_sgi_rx(wlc, 0);
+ }
+
+ /* initialize radio_mpc_disable according to wlc->mpc */
+ brcms_c_radio_mpc_upd(wlc);
+ brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
+
+ if (perr)
+ *perr = 0;
+
+ return wlc;
- return simple_strtoul(val, NULL, 0);
+ fail:
+ wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",
+ unit, __func__, err);
+ if (wlc)
+ brcms_c_detach(wlc);
+
+ if (perr)
+ *perr = err;
+ return NULL;
}
diff --git a/drivers/staging/brcm80211/brcmsmac/main.h b/drivers/staging/brcm80211/brcmsmac/main.h
index f204b1f47475..c0e0fcfdfaf8 100644
--- a/drivers/staging/brcm80211/brcmsmac/main.h
+++ b/drivers/staging/brcm80211/brcmsmac/main.h
@@ -22,35 +22,23 @@
#include <brcmu_utils.h>
#include "types.h"
#include "d11.h"
+#include "scb.h"
-#define MA_WINDOW_SZ 8 /* moving average window size */
-#define BRCMS_HWRXOFF 38 /* chip rx buffer offset */
#define INVCHANNEL 255 /* invalid channel */
-/* max # supported core revisions (0 .. MAXCOREREV - 1) */
-#define MAXCOREREV 28
+
/* max # brcms_c_module_register() calls */
#define BRCMS_MAXMODULES 22
#define SEQNUM_SHIFT 4
-#define AMPDU_DELIMITER_LEN 4
#define SEQNUM_MAX 0x1000
-#define APHY_CWMIN 15
-#define PHY_CWMAX 1023
-
-#define EDCF_AIFSN_MIN 1
-#define FRAGNUM_MASK 0xF
-
#define NTXRATE 64 /* # tx MPDUs rate is reported for */
-#define BRCMS_BITSCNT(x) brcmu_bitcount((u8 *)&(x), sizeof(u8))
-
/* Maximum wait time for a MAC suspend */
/* uS: 83mS is max packet time (64KB ampdu @ 6Mbps) */
#define BRCMS_MAX_MAC_SUSPEND 83000
-/* Probe Response timeout - responses for probe requests older that this are tossed, zero to disable
- */
+/* responses for probe requests older that this are tossed, zero to disable */
#define BRCMS_PRB_RESP_TIMEOUT 0 /* Disable probe response timeout */
/* transmit buffer max headroom for protocol headers */
@@ -78,13 +66,14 @@
#define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */
+/* max # supported core revisions (0 .. MAXCOREREV - 1) */
+#define MAXCOREREV 28
+
/* Double check that unsupported cores are not enabled */
#if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV)
#error "Configuration for D11CONF includes unsupported versions."
#endif /* Bad versions */
-#define VALID_COREREV(corerev) CONF_HAS(D11CONF, corerev)
-
/* values for shortslot_override */
#define BRCMS_SHORTSLOT_AUTO -1 /* Driver will manage Shortslot setting */
#define BRCMS_SHORTSLOT_OFF 0 /* Turn off short slot */
@@ -98,17 +87,6 @@
#define BRCMS_IS_MIMO_PREAMBLE(_pre) (((_pre) == BRCMS_GF_PREAMBLE) || \
((_pre) == BRCMS_MM_PREAMBLE))
-/* values for barker_preamble */
-#define BRCMS_BARKER_SHORT_ALLOWED 0 /* Short pre-amble allowed */
-
-/* A fifo is full. Clear precedences related to that FIFO */
-#define BRCMS_TX_FIFO_CLEAR(wlc, fifo) \
- ((wlc)->tx_prec_map &= ~(wlc)->fifo2prec_map[fifo])
-
-/* Fifo is NOT full. Enable precedences for that FIFO */
-#define BRCMS_TX_FIFO_ENAB(wlc, fifo) \
- ((wlc)->tx_prec_map |= (wlc)->fifo2prec_map[fifo])
-
/* TxFrameID */
/* seq and frag bits: SEQNUM_SHIFT, FRAGNUM_MASK (802.11.h) */
/* rate epoch bits: TXFID_RATE_SHIFT, TXFID_RATE_MASK ((wlc_rate.c) */
@@ -123,18 +101,6 @@
#define BOARDREV_PROMOTABLE 0xFF /* from */
#define BOARDREV_PROMOTED 1 /* to */
-/* if wpa is in use then portopen is true when the group key is plumbed otherwise it is always true
- */
-#define WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
-#define BRCMS_SW_KEYS(wlc, bsscfg) ((((wlc)->wsec_swkeys) || \
- ((bsscfg)->wsec & WSEC_SWFLAG)))
-
-#define BRCMS_PORTOPEN(cfg) \
- (((cfg)->WPA_auth != WPA_AUTH_DISABLED && WSEC_ENABLED((cfg)->wsec)) ? \
- (cfg)->wsec_portopen : true)
-
-#define PS_ALLOWED(wlc) brcms_c_ps_allowed(wlc)
-
#define DATA_BLOCK_TX_SUPR (1 << 4)
/* 802.1D Priority to TX FIFO number for wme */
@@ -160,48 +126,14 @@ extern const u8 prio2fifo[];
MI_PHYTXERR | MI_DMAINT | MI_TFS | MI_BG_NOISE | \
MI_CCA | MI_TO | MI_GP0 | MI_RFDISABLE | MI_PWRUP)
-#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */
-#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */
-#define RETRY_LONG_DEF 4 /* Default Long retry count */
-#define RETRY_SHORT_FB 3 /* Short retry count for fallback rate */
-#define RETRY_LONG_FB 2 /* Long retry count for fallback rate */
-
#define MAXTXPKTS 6 /* max # pkts pending */
/* frameburst */
-#define MAXTXFRAMEBURST 8 /* vanilla xpress mode: max frames/burst */
+#define MAXTXFRAMEBURST 8 /* vanilla xpress mode: max frames/burst */
#define MAXFRAMEBURST_TXOP 10000 /* Frameburst TXOP in usec */
-/* Per-AC retry limit register definitions; uses defs.h bitfield macros */
-#define EDCF_SHORT_S 0
-#define EDCF_SFB_S 4
-#define EDCF_LONG_S 8
-#define EDCF_LFB_S 12
-#define EDCF_SHORT_M BITFIELD_MASK(4)
-#define EDCF_SFB_M BITFIELD_MASK(4)
-#define EDCF_LONG_M BITFIELD_MASK(4)
-#define EDCF_LFB_M BITFIELD_MASK(4)
-
#define NFIFO 6 /* # tx/rx fifopairs */
-#define BRCMS_WME_RETRY_SHORT_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_SHORT)
-#define BRCMS_WME_RETRY_SFB_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_SFB)
-#define BRCMS_WME_RETRY_LONG_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_LONG)
-#define BRCMS_WME_RETRY_LFB_GET(wlc, ac) \
- GFIELD(wlc->wme_retries[ac], EDCF_LFB)
-
-#define BRCMS_WME_RETRY_SHORT_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_SHORT, val))
-#define BRCMS_WME_RETRY_SFB_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_SFB, val))
-#define BRCMS_WME_RETRY_LONG_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_LONG, val))
-#define BRCMS_WME_RETRY_LFB_SET(wlc, ac, val) \
- (wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], EDCF_LFB, val))
-
/* PLL requests */
/* pll is shared on old chips */
@@ -211,83 +143,86 @@ extern const u8 prio2fifo[];
/* hold/release pll for some short operation */
#define BRCMS_PLLREQ_FLIP 0x4
-/*
- * Macros to check if AP or STA is active.
- * AP Active means more than just configured: driver and BSS are "up";
- * that is, we are beaconing/responding as an AP (aps_associated).
- * STA Active similarly means the driver is up and a configured STA BSS
- * is up: either associated (stas_associated) or trying.
- *
- * Macro definitions vary as per AP/STA ifdefs, allowing references to
- * ifdef'd structure fields and constant values (0) for optimization.
- * Make sure to enclose blocks of code such that any routines they
- * reference can also be unused and optimized out by the linker.
- */
-/* NOTE: References structure fields defined in wlc.h */
-#define AP_ACTIVE(wlc) (0)
-
-/*
- * Detect Card removed.
- * Even checking an sbconfig register read will not false trigger when the core is in reset.
- * it breaks CF address mechanism. Accessing gphy phyversion will cause SB error if aphy
- * is in reset on 4306B0-DB. Need a simple accessible reg with fixed 0/1 pattern
- * (some platforms return all 0).
- * If clocks are present, call the sb routine which will figure out if the device is removed.
- */
-#define DEVICEREMOVED(wlc) \
- ((wlc->hw->clk) ? \
- ((R_REG(&wlc->hw->regs->maccontrol) & \
- (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN) : \
- (ai_deviceremoved(wlc->hw->sih)))
+#define CHANNEL_BANDUNIT(wlc, ch) \
+ (((ch) <= CH_MAX_2G_CHANNEL) ? BAND_2G_INDEX : BAND_5G_INDEX)
-#define BRCMS_UNIT(wlc) ((wlc)->pub->unit)
+#define OTHERBANDUNIT(wlc) \
+ ((uint)((wlc)->band->bandunit ? BAND_2G_INDEX : BAND_5G_INDEX))
+/*
+ * 802.11 protection information
+ *
+ * _g: use g spec protection, driver internal.
+ * g_override: override for use of g spec protection.
+ * gmode_user: user config gmode, operating band->gmode is different.
+ * overlap: Overlap BSS/IBSS protection for both 11g and 11n.
+ * nmode_user: user config nmode, operating pub->nmode is different.
+ * n_cfg: use OFDM protection on MIMO frames.
+ * n_cfg_override: override for use of N protection.
+ * nongf: non-GF present protection.
+ * nongf_override: override for use of GF protection.
+ * n_pam_override: override for preamble: MM or GF.
+ * n_obss: indicated OBSS Non-HT STA present.
+*/
struct brcms_protection {
- bool _g; /* use g spec protection, driver internal */
- s8 g_override; /* override for use of g spec protection */
- u8 gmode_user; /* user config gmode, operating band->gmode is different */
- s8 overlap; /* Overlap BSS/IBSS protection for both 11g and 11n */
- s8 nmode_user; /* user config nmode, operating pub->nmode is different */
- s8 n_cfg; /* use OFDM protection on MIMO frames */
- s8 n_cfg_override; /* override for use of N protection */
- bool nongf; /* non-GF present protection */
- s8 nongf_override; /* override for use of GF protection */
- s8 n_pam_override; /* override for preamble: MM or GF */
- bool n_obss; /* indicated OBSS Non-HT STA present */
+ bool _g;
+ s8 g_override;
+ u8 gmode_user;
+ s8 overlap;
+ s8 nmode_user;
+ s8 n_cfg;
+ s8 n_cfg_override;
+ bool nongf;
+ s8 nongf_override;
+ s8 n_pam_override;
+ bool n_obss;
};
-/* anything affects the single/dual streams/antenna operation */
+/*
+ * anything affecting the single/dual streams/antenna operation
+ *
+ * hw_txchain: HW txchain bitmap cfg.
+ * txchain: txchain bitmap being used.
+ * txstreams: number of txchains being used.
+ * hw_rxchain: HW rxchain bitmap cfg.
+ * rxchain: rxchain bitmap being used.
+ * rxstreams: number of rxchains being used.
+ * ant_rx_ovr: rx antenna override.
+ * txant: userTx antenna setting.
+ * phytxant: phyTx antenna setting in txheader.
+ * ss_opmode: singlestream Operational mode, 0:siso; 1:cdd.
+ * ss_algosel_auto: if true, use wlc->stf->ss_algo_channel;
+ * else use wlc->band->stf->ss_mode_band.
+ * ss_algo_channel: ss based on per-channel algo: 0: SISO, 1: CDD 2: STBC.
+ * rxchain_restore_delay: delay time to restore default rxchain.
+ * ldpc: AUTO/ON/OFF ldpc cap supported.
+ * txcore[MAX_STREAMS_SUPPORTED + 1]: bitmap of selected core for each Nsts.
+ * spatial_policy:
+ */
struct brcms_stf {
- u8 hw_txchain; /* HW txchain bitmap cfg */
- u8 txchain; /* txchain bitmap being used */
- u8 txstreams; /* number of txchains being used */
-
- u8 hw_rxchain; /* HW rxchain bitmap cfg */
- u8 rxchain; /* rxchain bitmap being used */
- u8 rxstreams; /* number of rxchains being used */
-
- u8 ant_rx_ovr; /* rx antenna override */
- s8 txant; /* userTx antenna setting */
- u16 phytxant; /* phyTx antenna setting in txheader */
-
- u8 ss_opmode; /* singlestream Operational mode, 0:siso; 1:cdd */
- bool ss_algosel_auto; /* if true, use wlc->stf->ss_algo_channel; */
- /* else use wlc->band->stf->ss_mode_band; */
- u16 ss_algo_channel; /* ss based on per-channel algo: 0: SISO, 1: CDD 2: STBC */
- u8 no_cddstbc; /* stf override, 1: no CDD (or STBC) allowed */
-
- u8 rxchain_restore_delay; /* delay time to restore default rxchain */
-
- s8 ldpc; /* AUTO/ON/OFF ldpc cap supported */
- u8 txcore[MAX_STREAMS_SUPPORTED + 1]; /* bitmap of selected core for each Nsts */
+ u8 hw_txchain;
+ u8 txchain;
+ u8 txstreams;
+ u8 hw_rxchain;
+ u8 rxchain;
+ u8 rxstreams;
+ u8 ant_rx_ovr;
+ s8 txant;
+ u16 phytxant;
+ u8 ss_opmode;
+ bool ss_algosel_auto;
+ u16 ss_algo_channel;
+ u8 rxchain_restore_delay;
+ s8 ldpc;
+ u8 txcore[MAX_STREAMS_SUPPORTED + 1];
s8 spatial_policy;
};
#define BRCMS_STF_SS_STBC_TX(wlc, scb) \
- (((wlc)->stf->txstreams > 1) && (((wlc)->band->band_stf_stbc_tx == ON) || \
- (SCB_STBC_CAP((scb)) && \
- (wlc)->band->band_stf_stbc_tx == AUTO && \
- isset(&((wlc)->stf->ss_algo_channel), PHY_TXC1_MODE_STBC))))
+ (((wlc)->stf->txstreams > 1) && (((wlc)->band->band_stf_stbc_tx == ON) \
+ || (((scb)->flags & SCB_STBCCAP) && \
+ (wlc)->band->band_stf_stbc_tx == AUTO && \
+ isset(&((wlc)->stf->ss_algo_channel), PHY_TXC1_MODE_STBC))))
#define BRCMS_STBC_CAP_PHY(wlc) (BRCMS_ISNPHY(wlc->band) && \
NREV_GE(wlc->band->phyrev, 3))
@@ -300,60 +235,6 @@ struct brcms_stf {
>> RXS_CHAN_PHYTYPE_SHIFT)
#define BRCMS_CHAN_CHANNEL(x) (((x) & RXS_CHAN_ID_MASK) \
>> RXS_CHAN_ID_SHIFT)
-#define BRCMS_RX_CHANNEL(rxh) (BRCMS_CHAN_CHANNEL((rxh)->RxChan))
-
-/* brcms_bss_info flag bit values */
-#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */
-
-/* Flags used in brcms_c_txq_info.stopped */
-#define TXQ_STOP_FOR_PRIOFC_MASK 0x000000FF /* per prio flow control bits */
-#define TXQ_STOP_FOR_PKT_DRAIN 0x00000100 /* stop txq enqueue for packet drain */
-#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL 0x00000200 /* stop txq enqueue for ampdu flow control */
-
-#define BRCMS_HT_WEP_RESTRICT 0x01 /* restrict HT with WEP */
-#define BRCMS_HT_TKIP_RESTRICT 0x02 /* restrict HT with TKIP */
-
-/* Maximum # of keys that wl driver supports in S/W.
- * Keys supported in H/W is less than or equal to WSEC_MAX_KEYS.
- */
-#define WSEC_MAX_KEYS 54 /* Max # of keys (50 + 4 default keys) */
-#define BRCMS_DEFAULT_KEYS 4 /* Default # of keys */
-
-/*
-* Max # of keys currently supported:
-*
-* s/w keys if WSEC_SW(wlc->wsec).
-* h/w keys otherwise.
-*/
-#define BRCMS_MAX_WSEC_KEYS(wlc) WSEC_MAX_KEYS
-
-/* number of 802.11 default (non-paired, group keys) */
-#define WSEC_MAX_DEFAULT_KEYS 4 /* # of default keys */
-
-struct wsec_iv {
- u32 hi; /* upper 32 bits of IV */
- u16 lo; /* lower 16 bits of IV */
-};
-
-#define BRCMS_NUMRXIVS 16 /* # rx IVs (one per 802.11e TID) */
-
-struct wsec_key {
- u8 ea[ETH_ALEN]; /* per station */
- u8 idx; /* key index in wsec_keys array */
- u8 id; /* key ID [0-3] */
- u8 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */
- u8 rcmta; /* rcmta entry index, same as idx by default */
- u16 flags; /* misc flags */
- u8 algo_hw; /* cache for hw register */
- u8 aes_mode; /* cache for hw register */
- s8 iv_len; /* IV length */
- s8 icv_len; /* ICV length */
- u32 len; /* key length..don't move this var */
- /* data is 4byte aligned */
- u8 data[WLAN_MAX_KEY_LEN]; /* key data */
- struct wsec_iv rxiv[BRCMS_NUMRXIVS]; /* Rx IV (one per TID) */
- struct wsec_iv txiv; /* Tx IV */
-};
/*
* core state (mac)
@@ -386,92 +267,37 @@ struct brcms_band {
struct scb *hwrs_scb; /* permanent scb for hw rateset */
- wlc_rateset_t defrateset; /* band-specific copy of default_bss.rateset */
+ /* band-specific copy of default_bss.rateset */
+ struct brcms_c_rateset defrateset;
- ratespec_t rspec_override; /* 802.11 rate override */
- ratespec_t mrspec_override; /* multicast rate override */
u8 band_stf_ss_mode; /* Configured STF type, 0:siso; 1:cdd */
s8 band_stf_stbc_tx; /* STBC TX 0:off; 1:force on; -1:auto */
- wlc_rateset_t hw_rateset; /* rates supported by chip (phy-specific) */
+ /* rates supported by chip (phy-specific) */
+ struct brcms_c_rateset hw_rateset;
u8 basic_rate[BRCM_MAXRATE + 1]; /* basic rates indexed by rate */
bool mimo_cap_40; /* 40 MHz cap enabled on this band */
s8 antgain; /* antenna gain from srom */
- u16 CWmin; /* The minimum size of contention window, in unit of aSlotTime */
- u16 CWmax; /* The maximum size of contention window, in unit of aSlotTime */
- u16 bcntsfoff; /* beacon tsf offset */
-};
-
-/* tx completion callback takes 3 args */
-typedef void (*pkcb_fn_t) (struct brcms_c_info *wlc, uint txstatus, void *arg);
-
-struct pkt_cb {
- pkcb_fn_t fn; /* function to call when tx frame completes */
- void *arg; /* void arg for fn */
- u8 nextidx; /* index of next call back if threading */
- bool entered; /* recursion check */
+ u16 CWmin; /* minimum size of contention window, in unit of aSlotTime */
+ u16 CWmax; /* maximum size of contention window, in unit of aSlotTime */
+ struct ieee80211_supported_band band;
};
/* module control blocks */
struct modulecb {
- char name[32]; /* module name : NULL indicates empty array member */
- const struct brcmu_iovar *iovars; /* iovar table */
- void *hdl; /* handle passed when handler 'doiovar' is called */
- watchdog_fn_t watchdog_fn; /* watchdog handler */
- iovar_fn_t iovar_fn; /* iovar handler */
- down_fn_t down_fn; /* down handler. Note: the int returned
- * by the down function is a count of the
- * number of timers that could not be
- * freed.
- */
-};
+ /* module name : NULL indicates empty array member */
+ char name[32];
+ /* handle passed when handler 'doiovar' is called */
+ struct brcms_info *hdl;
-/* dump control blocks */
-struct dumpcb_s {
- const char *name; /* dump name */
- dump_fn_t dump_fn; /* 'wl dump' handler */
- void *dump_fn_arg;
- struct dumpcb_s *next;
-};
+ int (*down_fn)(void *handle); /* down handler. Note: the int returned
+ * by the down function is a count of the
+ * number of timers that could not be
+ * freed.
+ */
-struct edcf_acparam {
- u8 ACI;
- u8 ECW;
- u16 TXOP;
-} __packed;
-
-struct wme_param_ie {
- u8 oui[3];
- u8 type;
- u8 subtype;
- u8 version;
- u8 qosinfo;
- u8 rsvd;
- struct edcf_acparam acparam[AC_COUNT];
-} __packed;
-
-/* virtual interface */
-struct brcms_c_if {
- struct brcms_c_if *next;
- u8 type; /* BSS or WDS */
- u8 index; /* assigned in wl_add_if(), index of the wlif if any,
- * not necessarily corresponding to bsscfg._idx or
- * AID2PVBMAP(scb).
- */
- u8 flags; /* flags for the interface */
- struct brcms_if *wlif; /* pointer to wlif */
- struct brcms_txq_info *qi; /* pointer to associated tx queue */
- union {
- /* pointer to scb if WDS */
- struct scb *scb;
- /* pointer to bsscfg if BSS */
- struct brcms_bss_cfg *bsscfg;
- } u;
};
-/* flags for the interface, this interface is linked to a brcms_if */
-#define BRCMS_IF_LINKED 0x02
-
struct brcms_hw_band {
int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */
uint bandunit; /* bandstate[] index */
@@ -508,14 +334,11 @@ struct brcms_hardware {
u32 boardflags2; /* More board flags if sromrev >= 4 */
u32 machwcap; /* MAC capabilities */
u32 machwcap_backup; /* backup of machwcap */
- u16 ucode_dbgsel; /* dbgsel for ucode debug(config gpio) */
struct si_pub *sih; /* SI handle (cookie for siutils calls) */
- char *vars; /* "environment" name=value */
- uint vars_size; /* size of vars, free vars on detach */
- d11regs_t *regs; /* pointer to device registers */
- void *physhim; /* phy shim layer handler */
- void *phy_sh; /* pointer to shared phy state */
+ struct d11regs __iomem *regs; /* pointer to device registers */
+ struct phy_shim_info *physhim; /* phy shim layer handler */
+ struct shared_phy *phy_sh; /* pointer to shared phy state */
struct brcms_hw_band *band;/* pointer to active per-band state */
/* band state per phy/radio */
struct brcms_hw_band *bandstate[MAXBANDS];
@@ -529,27 +352,24 @@ struct brcms_hardware {
bool up; /* d11 hardware up and running */
uint now; /* # elapsed seconds */
uint _nbands; /* # bands supported */
- chanspec_t chanspec; /* bmac chanspec shadow */
+ u16 chanspec; /* bmac chanspec shadow */
uint *txavail[NFIFO]; /* # tx descriptors available */
- u16 *xmtfifo_sz; /* fifo size in 256B for each xmt fifo */
+ const u16 *xmtfifo_sz; /* fifo size in 256B for each xmt fifo */
- mbool pllreq; /* pll requests to keep PLL on */
+ u32 pllreq; /* pll requests to keep PLL on */
u8 suspended_fifos; /* Which TX fifo to remain awake for */
u32 maccontrol; /* Cached value of maccontrol */
uint mac_suspend_depth; /* current depth of mac_suspend levels */
- u32 wake_override; /* Various conditions to force MAC to WAKE mode */
+ u32 wake_override; /* bit flags to force MAC to WAKE mode */
u32 mute_override; /* Prevent ucode from sending beacons */
u8 etheraddr[ETH_ALEN]; /* currently configured ethernet address */
- u32 led_gpio_mask; /* LED GPIO Mask */
bool noreset; /* true= do not reset hw, used by WLC_OUT */
- bool forcefastclk; /* true if the h/w is forcing the use of fast clk */
+ bool forcefastclk; /* true if h/w is forcing to use fast clk */
bool clk; /* core is out of reset and has clock */
bool sbclk; /* sb has clock */
- struct bmac_pmq *bmac_pmq; /* bmac PM states derived from ucode PMQ */
bool phyclk; /* phy is out of reset and has clock */
- bool dma_lpbk; /* core is in DMA loopback */
bool ucode_loaded; /* true after ucode downloaded */
@@ -578,195 +398,212 @@ struct brcms_txq_info {
};
/*
- * Principal common (os-independent) software data structure.
+ * Principal common driver data structure.
+ *
+ * pub: pointer to driver public state.
+ * wl: pointer to specific private state.
+ * regs: pointer to device registers.
+ * hw: HW related state.
+ * clkreq_override: setting for clkreq for PCIE : Auto, 0, 1.
+ * fastpwrup_dly: time in us needed to bring up d11 fast clock.
+ * macintstatus: bit channel between isr and dpc.
+ * macintmask: sw runtime master macintmask value.
+ * defmacintmask: default "on" macintmask value.
+ * clk: core is out of reset and has clock.
+ * core: pointer to active io core.
+ * band: pointer to active per-band state.
+ * corestate: per-core state (one per hw core).
+ * bandstate: per-band state (one per phy/radio).
+ * qvalid: DirFrmQValid and BcMcFrmQValid.
+ * ampdu: ampdu module handler.
+ * asi: antsel module handler.
+ * cmi: channel manager module handler.
+ * vendorid: PCI vendor id.
+ * deviceid: PCI device id.
+ * ucode_rev: microcode revision.
+ * machwcap: MAC capabilities, BMAC shadow.
+ * perm_etheraddr: original sprom local ethernet address.
+ * bandlocked: disable auto multi-band switching.
+ * bandinit_pending: track band init in auto band.
+ * radio_monitor: radio timer is running.
+ * going_down: down path intermediate variable.
+ * mpc: enable minimum power consumption.
+ * mpc_dlycnt: # of watchdog cnt before turn disable radio.
+ * mpc_offcnt: # of watchdog cnt that radio is disabled.
+ * mpc_delay_off: delay radio disable by # of watchdog cnt.
+ * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc.
+ * wdtimer: timer for watchdog routine.
+ * radio_timer: timer for hw radio button monitor routine.
+ * monitor: monitor (MPDU sniffing) mode.
+ * bcnmisc_monitor: bcns promisc mode override for monitor.
+ * _rifs: enable per-packet rifs.
+ * bcn_li_bcn: beacon listen interval in # beacons.
+ * bcn_li_dtim: beacon listen interval in # dtims.
+ * WDarmed: watchdog timer is armed.
+ * WDlast: last time wlc_watchdog() was called.
+ * edcf_txop[AC_COUNT]: current txop for each ac.
+ * wme_retries: per-AC retry limits.
+ * tx_prec_map: Precedence map based on HW FIFO space.
+ * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
+ * bsscfg: set of BSS configurations, idx 0 is default and always valid.
+ * cfg: the primary bsscfg (can be AP or STA).
+ * tx_queues: common TX Queue list.
+ * modulecb:
+ * mimoft: SIGN or 11N.
+ * cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode.
+ * ofdm_40txbw: 11N, ofdm tx b/w override when in 40MHZ mode.
+ * mimo_40txbw: 11N, mimo tx b/w override when in 40MHZ mode.
+ * default_bss: configured BSS parameters.
+ * mc_fid_counter: BC/MC FIFO frame ID counter.
+ * country_default: saved country for leaving 802.11d auto-country mode.
+ * autocountry_default: initial country for 802.11d auto-country mode.
+ * prb_resp_timeout: do not send prb resp if request older
+ * than this, 0 = disable.
+ * home_chanspec: shared home chanspec.
+ * chanspec: target operational channel.
+ * usr_fragthresh: user configured fragmentation threshold.
+ * fragthresh[NFIFO]: per-fifo fragmentation thresholds.
+ * RTSThresh: 802.11 dot11RTSThreshold.
+ * SRL: 802.11 dot11ShortRetryLimit.
+ * LRL: 802.11 dot11LongRetryLimit.
+ * SFBL: Short Frame Rate Fallback Limit.
+ * LFBL: Long Frame Rate Fallback Limit.
+ * shortslot: currently using 11g ShortSlot timing.
+ * shortslot_override: 11g ShortSlot override.
+ * include_legacy_erp: include Legacy ERP info elt ID 47 as well as g ID 42.
+ * PLCPHdr_override: 802.11b Preamble Type override.
+ * stf:
+ * bcn_rspec: save bcn ratespec purpose.
+ * tempsense_lasttime;
+ * tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM.
+ * tx_duty_cycle_cck: maximum allowed duty cycle for CCK.
+ * pkt_queue: txq for transmit packets.
+ * wiphy:
+ * pri_scb: primary Station Control Block
*/
struct brcms_c_info {
- struct brcms_pub *pub; /* pointer to wlc public state */
- struct brcms_info *wl; /* pointer to os-specific private state */
- d11regs_t *regs; /* pointer to device registers */
-
- /* HW related state used primarily by BMAC */
+ struct brcms_pub *pub;
+ struct brcms_info *wl;
+ struct d11regs __iomem *regs;
struct brcms_hardware *hw;
/* clock */
- int clkreq_override; /* setting for clkreq for PCIE : Auto, 0, 1 */
- u16 fastpwrup_dly; /* time in us needed to bring up d11 fast clock */
+ u16 fastpwrup_dly;
/* interrupt */
- u32 macintstatus; /* bit channel between isr and dpc */
- u32 macintmask; /* sw runtime master macintmask value */
- u32 defmacintmask; /* default "on" macintmask value */
-
- /* up and down */
- bool device_present; /* (removable) device is present */
+ u32 macintstatus;
+ u32 macintmask;
+ u32 defmacintmask;
- bool clk; /* core is out of reset and has clock */
+ bool clk;
/* multiband */
- struct brcms_core *core; /* pointer to active io core */
- struct brcms_band *band; /* pointer to active per-band state */
- struct brcms_core *corestate; /* per-core state (one per hw core) */
- /* per-band state (one per phy/radio): */
+ struct brcms_core *core;
+ struct brcms_band *band;
+ struct brcms_core *corestate;
struct brcms_band *bandstate[MAXBANDS];
- bool war16165; /* PCI slow clock 16165 war flag */
-
- bool tx_suspended; /* data fifos need to remain suspended */
-
- uint txpend16165war;
-
/* packet queue */
- uint qvalid; /* DirFrmQValid and BcMcFrmQValid */
-
- /* Regulatory power limits */
- s8 txpwr_local_max; /* regulatory local txpwr max */
- u8 txpwr_local_constraint; /* local power contraint in dB */
-
-
- struct ampdu_info *ampdu; /* ampdu module handler */
- struct antsel_info *asi; /* antsel module handler */
- struct brcms_cm_info *cmi; /* channel manager module handler */
+ uint qvalid;
- uint vars_size; /* size of vars, free vars on detach */
-
- u16 vendorid; /* PCI vendor id */
- u16 deviceid; /* PCI device id */
- uint ucode_rev; /* microcode revision */
+ struct ampdu_info *ampdu;
+ struct antsel_info *asi;
+ struct brcms_cm_info *cmi;
- u32 machwcap; /* MAC capabilities, BMAC shadow */
+ u16 vendorid;
+ u16 deviceid;
+ uint ucode_rev;
- u8 perm_etheraddr[ETH_ALEN]; /* original sprom local ethernet address */
+ u8 perm_etheraddr[ETH_ALEN];
- bool bandlocked; /* disable auto multi-band switching */
- bool bandinit_pending; /* track band init in auto band */
+ bool bandlocked;
+ bool bandinit_pending;
- bool radio_monitor; /* radio timer is running */
- bool going_down; /* down path intermediate variable */
+ bool radio_monitor;
+ bool going_down;
- bool mpc; /* enable minimum power consumption */
- u8 mpc_dlycnt; /* # of watchdog cnt before turn disable radio */
- u8 mpc_offcnt; /* # of watchdog cnt that radio is disabled */
- u8 mpc_delay_off; /* delay radio disable by # of watchdog cnt */
- u8 prev_non_delay_mpc; /* prev state brcms_c_is_non_delay_mpc */
+ bool mpc;
+ u8 mpc_dlycnt;
+ u8 mpc_offcnt;
+ u8 mpc_delay_off;
+ u8 prev_non_delay_mpc;
- /* timer for watchdog routine */
struct brcms_timer *wdtimer;
- /* timer for hw radio button monitor routine */
struct brcms_timer *radio_timer;
/* promiscuous */
- bool monitor; /* monitor (MPDU sniffing) mode */
- bool bcnmisc_ibss; /* bcns promisc mode override for IBSS */
- bool bcnmisc_scan; /* bcns promisc mode override for scan */
- bool bcnmisc_monitor; /* bcns promisc mode override for monitor */
+ bool monitor;
+ bool bcnmisc_monitor;
/* driver feature */
- bool _rifs; /* enable per-packet rifs */
- s8 sgi_tx; /* sgi tx */
+ bool _rifs;
/* AP-STA synchronization, power save */
- u8 bcn_li_bcn; /* beacon listen interval in # beacons */
- u8 bcn_li_dtim; /* beacon listen interval in # dtims */
+ u8 bcn_li_bcn;
+ u8 bcn_li_dtim;
- bool WDarmed; /* watchdog timer is armed */
- u32 WDlast; /* last time wlc_watchdog() was called */
+ bool WDarmed;
+ u32 WDlast;
/* WME */
- ac_bitmap_t wme_dp; /* Discard (oldest first) policy per AC */
- u16 edcf_txop[AC_COUNT]; /* current txop for each ac */
-
- /*
- * WME parameter info element, which on STA contains parameters in use
- * locally, and on AP contains parameters advertised to STA in beacons
- * and assoc responses.
- */
- struct wme_param_ie wme_param_ie;
- u16 wme_retries[AC_COUNT]; /* per-AC retry limits */
-
- u16 tx_prec_map; /* Precedence map based on HW FIFO space */
- u16 fifo2prec_map[NFIFO]; /* pointer to fifo2_prec map based on WME */
-
- /*
- * BSS Configurations set of BSS configurations, idx 0 is default and
- * always valid
- */
- struct brcms_bss_cfg *bsscfg[BRCMS_MAXBSSCFG];
- struct brcms_bss_cfg *cfg; /* the primary bsscfg (can be AP or STA) */
+ u16 edcf_txop[AC_COUNT];
+
+ u16 wme_retries[AC_COUNT];
+ u16 tx_prec_map;
+ u16 fifo2prec_map[NFIFO];
+
+ struct brcms_bss_cfg *bsscfg;
/* tx queue */
- struct brcms_txq_info *tx_queues; /* common TX Queue list */
-
- /* security */
- struct wsec_key *wsec_keys[WSEC_MAX_KEYS]; /* dynamic key storage */
- /* default key storage */
- struct wsec_key *wsec_def_keys[BRCMS_DEFAULT_KEYS];
- bool wsec_swkeys; /* indicates that all keys should be
- * treated as sw keys (used for debugging)
- */
+ struct brcms_txq_info *tx_queues;
+
struct modulecb *modulecb;
- u8 mimoft; /* SIGN or 11N */
- s8 cck_40txbw; /* 11N, cck tx b/w override when in 40MHZ mode */
- s8 ofdm_40txbw; /* 11N, ofdm tx b/w override when in 40MHZ mode */
- s8 mimo_40txbw; /* 11N, mimo tx b/w override when in 40MHZ mode */
- /* HT CAP IE being advertised by this node: */
- struct ieee80211_ht_cap ht_cap;
+ u8 mimoft;
+ s8 cck_40txbw;
+ s8 ofdm_40txbw;
+ s8 mimo_40txbw;
- struct brcms_bss_info *default_bss; /* configured BSS parameters */
+ struct brcms_bss_info *default_bss;
- u16 mc_fid_counter; /* BC/MC FIFO frame ID counter */
+ u16 mc_fid_counter;
- /* saved country for leaving 802.11d auto-country mode */
char country_default[BRCM_CNTRY_BUF_SZ];
- /* initial country for 802.11d auto-country mode */
char autocountry_default[BRCM_CNTRY_BUF_SZ];
- u16 prb_resp_timeout; /* do not send prb resp if request older than this,
- * 0 = disable
- */
-
- wlc_rateset_t sup_rates_override; /* use only these rates in 11g supported rates if
- * specifed
- */
+ u16 prb_resp_timeout;
- chanspec_t home_chanspec; /* shared home chanspec */
+ u16 home_chanspec;
/* PHY parameters */
- chanspec_t chanspec; /* target operational channel */
- u16 usr_fragthresh; /* user configured fragmentation threshold */
- u16 fragthresh[NFIFO]; /* per-fifo fragmentation thresholds */
- u16 RTSThresh; /* 802.11 dot11RTSThreshold */
- u16 SRL; /* 802.11 dot11ShortRetryLimit */
- u16 LRL; /* 802.11 dot11LongRetryLimit */
- u16 SFBL; /* Short Frame Rate Fallback Limit */
- u16 LFBL; /* Long Frame Rate Fallback Limit */
+ u16 chanspec;
+ u16 usr_fragthresh;
+ u16 fragthresh[NFIFO];
+ u16 RTSThresh;
+ u16 SRL;
+ u16 LRL;
+ u16 SFBL;
+ u16 LFBL;
/* network config */
- bool shortslot; /* currently using 11g ShortSlot timing */
- s8 shortslot_override; /* 11g ShortSlot override */
- bool include_legacy_erp; /* include Legacy ERP info elt ID 47 as well as g ID 42 */
+ bool shortslot;
+ s8 shortslot_override;
+ bool include_legacy_erp;
struct brcms_protection *protection;
- s8 PLCPHdr_override; /* 802.11b Preamble Type override */
+ s8 PLCPHdr_override;
struct brcms_stf *stf;
- ratespec_t bcn_rspec; /* save bcn ratespec purpose */
+ u32 bcn_rspec;
uint tempsense_lasttime;
- u16 tx_duty_cycle_ofdm; /* maximum allowed duty cycle for OFDM */
- u16 tx_duty_cycle_cck; /* maximum allowed duty cycle for CCK */
+ u16 tx_duty_cycle_ofdm;
+ u16 tx_duty_cycle_cck;
- u16 next_bsscfg_ID;
-
- struct brcms_txq_info *pkt_queue; /* txq for transmit packets */
- u32 mpc_dur; /* total time (ms) in mpc mode except for the
- * portion since radio is turned off last time
- */
- u32 mpc_laston_ts; /* timestamp (ms) when radio is turned off last
- * time
- */
+ struct brcms_txq_info *pkt_queue;
struct wiphy *wiphy;
+ struct scb pri_scb;
};
/* antsel module specific state */
@@ -782,244 +619,117 @@ struct antsel_info {
struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */
};
-/* BSS configuration state */
+/*
+ * BSS configuration state
+ *
+ * wlc: wlc to which this bsscfg belongs to.
+ * up: is this configuration up operational
+ * enable: is this configuration enabled
+ * associated: is BSS in ASSOCIATED state
+ * BSS: infraustructure or adhoc
+ * SSID_len: the length of SSID
+ * SSID: SSID string
+ *
+ *
+ * BSSID: BSSID (associated)
+ * cur_etheraddr: h/w address
+ * flags: BSSCFG flags; see below
+ *
+ * current_bss: BSS parms in ASSOCIATED state
+ *
+ *
+ * ID: 'unique' ID of this bsscfg, assigned at bsscfg allocation
+ */
struct brcms_bss_cfg {
- struct brcms_c_info *wlc; /* wlc to which this bsscfg belongs to. */
- bool up; /* is this configuration up operational */
- bool enable; /* is this configuration enabled */
- bool associated; /* is BSS in ASSOCIATED state */
- bool BSS; /* infraustructure or adhac */
- bool dtim_programmed;
-
- u8 SSID_len; /* the length of SSID */
- u8 SSID[IEEE80211_MAX_SSID_LEN]; /* SSID string */
- struct scb *bcmc_scb[MAXBANDS]; /* one bcmc_scb per band */
- s8 _idx; /* the index of this bsscfg,
- * assigned at wlc_bsscfg_alloc()
- */
- /* MAC filter */
- uint nmac; /* # of entries on maclist array */
- int macmode; /* allow/deny stations on maclist array */
- struct ether_addr *maclist; /* list of source MAC addrs to match */
-
- /* security */
- u32 wsec; /* wireless security bitvec */
- s16 auth; /* 802.11 authentication: Open, Shared Key, WPA */
- s16 openshared; /* try Open auth first, then Shared Key */
- bool wsec_restrict; /* drop unencrypted packets if wsec is enabled */
- bool eap_restrict; /* restrict data until 802.1X auth succeeds */
- u16 WPA_auth; /* WPA: authenticated key management */
- bool wpa2_preauth; /* default is true, wpa_cap sets value */
- bool wsec_portopen; /* indicates keys are plumbed */
- /* global txiv for WPA_NONE, tkip and aes */
- struct wsec_iv wpa_none_txiv;
- int wsec_index; /* 0-3: default tx key, -1: not set */
- /* default key storage: */
- struct wsec_key *bss_def_keys[BRCMS_DEFAULT_KEYS];
-
- /* TKIP countermeasures */
- bool tkip_countermeasures; /* flags TKIP no-assoc period */
- u32 tk_cm_dt; /* detect timer */
- u32 tk_cm_bt; /* blocking timer */
- u32 tk_cm_bt_tmstmp; /* Timestamp when TKIP BT is activated */
- bool tk_cm_activate; /* activate countermeasures after EAPOL-Key sent */
-
- u8 BSSID[ETH_ALEN]; /* BSSID (associated) */
- u8 cur_etheraddr[ETH_ALEN]; /* h/w address */
- u16 bcmc_fid; /* the last BCMC FID queued to TX_BCMC_FIFO */
- u16 bcmc_fid_shm; /* the last BCMC FID written to shared mem */
-
- u32 flags; /* BSSCFG flags; see below */
-
- u8 *bcn; /* AP beacon */
- uint bcn_len; /* AP beacon length */
- bool ar_disassoc; /* disassociated in associated recreation */
-
- int auth_atmptd; /* auth type (open/shared) attempted */
-
- pmkid_cand_t pmkid_cand[MAXPMKID]; /* PMKID candidate list */
- uint npmkid_cand; /* num PMKID candidates */
- pmkid_t pmkid[MAXPMKID]; /* PMKID cache */
- uint npmkid; /* num cached PMKIDs */
-
- struct brcms_bss_info *current_bss; /* BSS parms in ASSOCIATED state */
-
- /* PM states */
- bool PMawakebcn; /* bcn recvd during current waking state */
- bool PMpending; /* waiting for tx status with PM indicated set */
- bool priorPMstate; /* Detecting PM state transitions */
- bool PSpoll; /* whether there is an outstanding PS-Poll frame */
-
- /* BSSID entry in RCMTA, use the wsec key management infrastructure to
- * manage the RCMTA entries.
- */
- struct wsec_key *rcmta;
-
- /* 'unique' ID of this bsscfg, assigned at bsscfg allocation */
- u16 ID;
-
- uint txrspecidx; /* index into tx rate circular buffer */
- ratespec_t txrspec[NTXRATE][2]; /* circular buffer of prev MPDUs tx rates */
+ struct brcms_c_info *wlc;
+ bool up;
+ bool enable;
+ bool associated;
+ bool BSS;
+ u8 SSID_len;
+ u8 SSID[IEEE80211_MAX_SSID_LEN];
+ u8 BSSID[ETH_ALEN];
+ u8 cur_etheraddr[ETH_ALEN];
+ struct brcms_bss_info *current_bss;
};
-#define CHANNEL_BANDUNIT(wlc, ch) (((ch) <= CH_MAX_2G_CHANNEL) ? BAND_2G_INDEX : BAND_5G_INDEX)
-#define OTHERBANDUNIT(wlc) ((uint)((wlc)->band->bandunit ? BAND_2G_INDEX : BAND_5G_INDEX))
-
-#define IS_MBAND_UNLOCKED(wlc) \
- ((NBANDS(wlc) > 1) && !(wlc)->bandlocked)
-
-#define BRCMS_BAND_PI_RADIO_CHANSPEC wlc_phy_chanspec_get(wlc->band->pi)
-
-/* sum the individual fifo tx pending packet counts */
-#define TXPKTPENDTOT(wlc) ((wlc)->core->txpktpend[0] + (wlc)->core->txpktpend[1] + \
- (wlc)->core->txpktpend[2] + (wlc)->core->txpktpend[3])
-#define TXPKTPENDGET(wlc, fifo) ((wlc)->core->txpktpend[(fifo)])
-#define TXPKTPENDINC(wlc, fifo, val) ((wlc)->core->txpktpend[(fifo)] += (val))
-#define TXPKTPENDDEC(wlc, fifo, val) ((wlc)->core->txpktpend[(fifo)] -= (val))
-#define TXPKTPENDCLR(wlc, fifo) ((wlc)->core->txpktpend[(fifo)] = 0)
-#define TXAVAIL(wlc, fifo) (*(wlc)->core->txavail[(fifo)])
-#define GETNEXTTXP(wlc, _queue) \
- dma_getnexttxp((wlc)->hw->di[(_queue)], DMA_RANGE_TRANSMITTED)
-
-#define BRCMS_IS_MATCH_SSID(wlc, ssid1, ssid2, len1, len2) \
- ((len1 == len2) && !memcmp(ssid1, ssid2, len1))
-
-extern void brcms_c_fatal_error(struct brcms_c_info *wlc);
-extern void brcms_b_rpc_watchdog(struct brcms_c_info *wlc);
-extern void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p);
-extern bool brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs,
- u32 frm_tx2);
extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
struct sk_buff *p,
bool commit, s8 txpktpend);
extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo,
s8 txpktpend);
-extern void brcms_c_txq_enq(void *ctx, struct scb *scb, struct sk_buff *sdu,
- uint prec);
-extern void brcms_c_info_init(struct brcms_c_info *wlc, int unit);
+extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
+ struct sk_buff *sdu, uint prec);
extern void brcms_c_print_txstatus(struct tx_status *txs);
-extern int brcms_c_xmtfifo_sz_get(struct brcms_c_info *wlc, uint fifo,
- uint *blocks);
-extern void brcms_c_write_template_ram(struct brcms_c_info *wlc, int offset,
- int len, void *buf);
-extern void brcms_c_write_hw_bcntemplates(struct brcms_c_info *wlc, void *bcn,
- int len, bool both);
-extern void brcms_c_pllreq(struct brcms_c_info *wlc, bool set, mbool req_bit);
-extern void brcms_c_reset_bmac_done(struct brcms_c_info *wlc);
+extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
+ uint *blocks);
#if defined(BCMDBG)
-extern void brcms_c_print_rxh(struct d11rxhdr *rxh);
extern void brcms_c_print_txdesc(struct d11txh *txh);
#else
#define brcms_c_print_txdesc(a)
#endif
-extern void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit);
-extern void brcms_c_coredisable(struct brcms_hardware *wlc_hw);
-
-extern bool brcms_c_valid_rate(struct brcms_c_info *wlc, ratespec_t rate,
- int band, bool verbose);
-extern void brcms_c_ap_upd(struct brcms_c_info *wlc);
-
-/* helper functions */
-extern void brcms_c_shm_ssid_upd(struct brcms_c_info *wlc,
- struct brcms_bss_cfg *cfg);
extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
-
extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc,
bool promisc);
-extern void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc);
-extern void brcms_c_mac_promisc(struct brcms_c_info *wlc);
-extern void brcms_c_txflowcontrol(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi,
- bool on, int prio);
-extern void brcms_c_txflowcontrol_override(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi,
- bool on, uint override);
-extern bool brcms_c_txflowcontrol_prio_isset(struct brcms_c_info *wlc,
- struct brcms_txq_info *qi,
- int prio);
extern void brcms_c_send_q(struct brcms_c_info *wlc);
extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
uint *fifo);
-
-extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, ratespec_t ratespec,
+extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
uint mac_len);
-extern ratespec_t brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc,
- ratespec_t rspec,
+extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc,
+ u32 rspec,
bool use_rspec, u16 mimo_ctlchbw);
extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
- ratespec_t rts_rate,
- ratespec_t frame_rate,
+ u32 rts_rate,
+ u32 frame_rate,
u8 rts_preamble_type,
u8 frame_preamble_type, uint frame_len,
bool ba);
-
-extern void brcms_c_tbtt(struct brcms_c_info *wlc);
extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
struct ieee80211_sta *sta,
void (*dma_callback_fn));
-
-extern void brcms_c_reprate_init(struct brcms_c_info *wlc);
-extern void brcms_c_bsscfg_reprate_init(struct brcms_bss_cfg *bsscfg);
-
-/* Shared memory access */
-extern void brcms_c_write_shm(struct brcms_c_info *wlc, uint offset, u16 v);
-extern u16 brcms_c_read_shm(struct brcms_c_info *wlc, uint offset);
-extern void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,
- const void *buf, int len);
-
extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
-extern void brcms_c_bss_update_beacon(struct brcms_c_info *wlc,
- struct brcms_bss_cfg *bsscfg);
-
extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
-extern void brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,
- struct brcms_bss_cfg *cfg,
- bool suspend);
-extern bool brcms_c_ismpc(struct brcms_c_info *wlc);
-extern bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc);
-extern void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc);
-extern bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
- void *pkt, int prec);
-extern bool brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
- struct sk_buff *pkt, int prec, bool head);
-extern u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, ratespec_t rspec);
-extern void brcms_c_compute_plcp(struct brcms_c_info *wlc, ratespec_t rate,
- uint length, u8 *plcp);
-extern uint brcms_c_calc_frame_time(struct brcms_c_info *wlc,
- ratespec_t ratespec,
- u8 preamble_type, uint mac_len);
-
-extern void brcms_c_set_chanspec(struct brcms_c_info *wlc,
- chanspec_t chanspec);
-
-extern bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit);
-
-extern int brcms_c_set_nmode(struct brcms_c_info *wlc, s32 nmode);
-extern void brcms_c_mimops_action_ht_send(struct brcms_c_info *wlc,
- struct brcms_bss_cfg *bsscfg,
- u8 mimops_mode);
-
-extern void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot);
-extern void brcms_c_set_bssid(struct brcms_bss_cfg *cfg);
-extern void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend);
-
-extern void brcms_c_set_ratetable(struct brcms_c_info *wlc);
-extern int brcms_c_set_mac(struct brcms_bss_cfg *cfg);
+extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
- ratespec_t bcn_rate);
-extern void brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc,
- uint frame_len);
-extern ratespec_t brcms_c_lowest_basic_rspec(struct brcms_c_info *wlc,
- wlc_rateset_t *rs);
-extern void brcms_c_radio_disable(struct brcms_c_info *wlc);
-extern void brcms_c_bcn_li_upd(struct brcms_c_info *wlc);
-extern void brcms_c_set_home_chanspec(struct brcms_c_info *wlc,
- chanspec_t chanspec);
-extern bool brcms_c_ps_allowed(struct brcms_c_info *wlc);
-extern bool brcms_c_stay_awake(struct brcms_c_info *wlc);
-extern void brcms_c_wme_initparams_sta(struct brcms_c_info *wlc,
- struct wme_param_ie *pe);
+ u32 bcn_rate);
+extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw,
+ u8 antsel_type);
+extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw,
+ u16 chanspec,
+ bool mute, struct txpwr_limits *txpwr);
+extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset,
+ u16 v);
+extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset);
+extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask,
+ u16 val, int bands);
+extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags);
+extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val);
+extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw);
+extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw);
+extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw);
+extern void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,
+ u32 override_bit);
+extern void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,
+ u32 override_bit);
+extern void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw,
+ int offset, int len, void *buf);
+extern u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate);
+extern void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw,
+ uint offset, const void *buf, int len,
+ u32 sel);
+extern void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset,
+ void *buf, int len, u32 sel);
+extern void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode);
+extern u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw);
+extern void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk);
+extern void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk);
+extern void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on);
+extern void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant);
+extern void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw,
+ u8 stf_mode);
+extern void brcms_c_init_scb(struct scb *scb);
#endif /* _BRCM_MAIN_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/nicpci.c b/drivers/staging/brcm80211/brcmsmac/nicpci.c
index 3d71c590fcef..0bcb26792046 100644
--- a/drivers/staging/brcm80211/brcmsmac/nicpci.c
+++ b/drivers/staging/brcm80211/brcmsmac/nicpci.c
@@ -127,6 +127,18 @@
/* PCIE protocol TLP diagnostic registers */
#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
+/* Sonics to PCI translation types */
+#define SBTOPCI_PREF 0x4 /* prefetch enable */
+#define SBTOPCI_BURST 0x8 /* burst enable */
+#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
+
+#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
+
+/* PCI core index in SROM shadow area */
+#define SRSH_PI_OFFSET 0 /* first word */
+#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
+#define SRSH_PI_SHIFT 12 /* bit 15:12 */
+
/* Sonics side: PCI core and host control registers */
struct sbpciregs {
u32 control; /* PCI control */
@@ -194,8 +206,8 @@ struct sbpcieregs {
struct pcicore_info {
union {
- struct sbpcieregs *pcieregs;
- struct sbpciregs *pciregs;
+ struct sbpcieregs __iomem *pcieregs;
+ struct sbpciregs __iomem *pciregs;
} regs; /* Memory mapped register to the core */
struct si_pub *sih; /* System interconnect handle */
@@ -211,52 +223,30 @@ struct pcicore_info {
bool pmecap; /* Capable of generating PME */
};
-/* debug/trace */
-#define PCI_ERROR(args)
-#define PCIE_PUB(sih) \
- (((sih)->bustype == PCI_BUS) && \
- ((sih)->buscoretype == PCIE_CORE_ID))
-
-/* routines to access mdio slave device registers */
-static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk);
-static int pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr,
- bool write, uint *val);
-static int pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint readdr,
- uint val);
-static int pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint readdr,
- uint *ret_val);
-
-static void pcie_extendL1timer(struct pcicore_info *pi, bool extend);
-static void pcie_clkreq_upd(struct pcicore_info *pi, uint state);
-
-static void pcie_war_aspm_clkreq(struct pcicore_info *pi);
-static void pcie_war_serdes(struct pcicore_info *pi);
-static void pcie_war_noplldown(struct pcicore_info *pi);
-static void pcie_war_polarity(struct pcicore_info *pi);
-static void pcie_war_pci_setup(struct pcicore_info *pi);
-
#define PCIE_ASPM(sih) \
- ((PCIE_PUB(sih)) && \
+ (((sih)->buscoretype == PCIE_CORE_ID) && \
(((sih)->buscorerev >= 3) && \
((sih)->buscorerev <= 5)))
/* delay needed between the mdio control/ mdiodata register data access */
-#define PR28829_DELAY() udelay(10)
+static void pr28829_delay(void)
+{
+ udelay(10);
+}
/* Initialize the PCI core.
* It's caller's responsibility to make sure that this is done only once
*/
-void *pcicore_init(struct si_pub *sih, void *pdev, void *regs)
+struct pcicore_info *pcicore_init(struct si_pub *sih, struct pci_dev *pdev,
+ void __iomem *regs)
{
struct pcicore_info *pi;
/* alloc struct pcicore_info */
pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC);
- if (pi == NULL) {
- PCI_ERROR(("pci_attach: malloc failed!\n"));
+ if (pi == NULL)
return NULL;
- }
pi->sih = sih;
pi->dev = pdev;
@@ -273,7 +263,7 @@ void *pcicore_init(struct si_pub *sih, void *pdev, void *regs)
return pi;
}
-void pcicore_deinit(void *pch)
+void pcicore_deinit(struct pcicore_info *pch)
{
kfree(pch);
}
@@ -281,7 +271,7 @@ void pcicore_deinit(void *pch)
/* return cap_offset if requested capability exists in the PCI config space */
/* Note that it's caller's responsibility to make sure it's a pci bus */
u8
-pcicore_find_pci_capability(void *dev, u8 req_cap_id,
+pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
unsigned char *buf, u32 *buflen)
{
u8 cap_id;
@@ -344,7 +334,7 @@ end:
/* ***** Register Access API */
static uint
-pcie_readreg(struct sbpcieregs *pcieregs, uint addrtype, uint offset)
+pcie_readreg(struct sbpcieregs __iomem *pcieregs, uint addrtype, uint offset)
{
uint retval = 0xFFFFFFFF;
@@ -364,8 +354,8 @@ pcie_readreg(struct sbpcieregs *pcieregs, uint addrtype, uint offset)
return retval;
}
-static uint
-pcie_writereg(struct sbpcieregs *pcieregs, uint addrtype, uint offset, uint val)
+static uint pcie_writereg(struct sbpcieregs __iomem *pcieregs, uint addrtype,
+ uint offset, uint val)
{
switch (addrtype) {
case PCIE_CONFIGREGS:
@@ -384,7 +374,7 @@ pcie_writereg(struct sbpcieregs *pcieregs, uint addrtype, uint offset, uint val)
static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk)
{
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
uint mdiodata, i = 0;
uint pcie_serdes_spinwait = 200;
@@ -394,19 +384,18 @@ static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk)
(blk << 4));
W_REG(&pcieregs->mdiodata, mdiodata);
- PR28829_DELAY();
+ pr28829_delay();
/* retry till the transaction is complete */
while (i < pcie_serdes_spinwait) {
if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE)
break;
+
udelay(1000);
i++;
}
- if (i >= pcie_serdes_spinwait) {
- PCI_ERROR(("pcie_mdiosetblock: timed out\n"));
+ if (i >= pcie_serdes_spinwait)
return false;
- }
return true;
}
@@ -415,7 +404,7 @@ static int
pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
uint *val)
{
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
uint mdiodata;
uint i = 0;
uint pcie_serdes_spinwait = 10;
@@ -445,13 +434,13 @@ pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
W_REG(&pcieregs->mdiodata, mdiodata);
- PR28829_DELAY();
+ pr28829_delay();
/* retry till the transaction is complete */
while (i < pcie_serdes_spinwait) {
if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) {
if (!write) {
- PR28829_DELAY();
+ pr28829_delay();
*val = (R_REG(&pcieregs->mdiodata) &
MDIODATA_MASK);
}
@@ -463,8 +452,7 @@ pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
i++;
}
- PCI_ERROR(("pcie_mdioop: timed out op: %d\n", write));
- /* Disable mdio access to SERDES */
+ /* Timed out. Disable mdio access to SERDES. */
W_REG(&pcieregs->mdiocontrol, 0);
return 1;
}
@@ -485,9 +473,8 @@ pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val)
}
/* ***** Support functions ***** */
-static u8 pcie_clkreq(void *pch, u32 mask, u32 val)
+static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val)
{
- struct pcicore_info *pi = pch;
u32 reg_val;
u8 offset;
@@ -515,9 +502,9 @@ static void pcie_extendL1timer(struct pcicore_info *pi, bool extend)
{
u32 w;
struct si_pub *sih = pi->sih;
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
- if (!PCIE_PUB(sih) || sih->buscorerev < 7)
+ if (sih->buscoretype != PCIE_CORE_ID || sih->buscorerev < 7)
return;
w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
@@ -537,30 +524,30 @@ static void pcie_clkreq_upd(struct pcicore_info *pi, uint state)
switch (state) {
case SI_DOATTACH:
if (PCIE_ASPM(sih))
- pcie_clkreq((void *)pi, 1, 0);
+ pcie_clkreq(pi, 1, 0);
break;
case SI_PCIDOWN:
if (sih->buscorerev == 6) { /* turn on serdes PLL down */
ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_addr),
+ offsetof(struct chipcregs, chipcontrol_addr),
~0, 0);
ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_data),
+ offsetof(struct chipcregs, chipcontrol_data),
~0x40, 0);
} else if (pi->pcie_pr42767) {
- pcie_clkreq((void *)pi, 1, 1);
+ pcie_clkreq(pi, 1, 1);
}
break;
case SI_PCIUP:
if (sih->buscorerev == 6) { /* turn off serdes PLL down */
ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_addr),
+ offsetof(struct chipcregs, chipcontrol_addr),
~0, 0);
ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_data),
+ offsetof(struct chipcregs, chipcontrol_data),
~0x40, 0x40);
} else if (PCIE_ASPM(sih)) { /* disable clkreq */
- pcie_clkreq((void *)pi, 1, 0);
+ pcie_clkreq(pi, 1, 0);
}
break;
}
@@ -594,9 +581,10 @@ static void pcie_war_polarity(struct pcicore_info *pi)
*/
static void pcie_war_aspm_clkreq(struct pcicore_info *pi)
{
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
struct si_pub *sih = pi->sih;
- u16 val16, *reg16;
+ u16 val16;
+ u16 __iomem *reg16;
u32 w;
if (!PCIE_ASPM(sih))
@@ -654,8 +642,9 @@ static void pcie_war_serdes(struct pcicore_info *pi)
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_misc_config_fixup(struct pcicore_info *pi)
{
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
- u16 val16, *reg16;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ u16 val16;
+ u16 __iomem *reg16;
reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG];
val16 = R_REG(reg16);
@@ -670,11 +659,11 @@ static void pcie_misc_config_fixup(struct pcicore_info *pi)
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_noplldown(struct pcicore_info *pi)
{
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
- u16 *reg16;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
+ u16 __iomem *reg16;
/* turn off serdes PLL down */
- ai_corereg(pi->sih, SI_CC_IDX, offsetof(chipcregs_t, chipcontrol),
+ ai_corereg(pi->sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol),
CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
/* clear srom shadow backdoor */
@@ -686,7 +675,7 @@ static void pcie_war_noplldown(struct pcicore_info *pi)
static void pcie_war_pci_setup(struct pcicore_info *pi)
{
struct si_pub *sih = pi->sih;
- struct sbpcieregs *pcieregs = pi->regs.pcieregs;
+ struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs;
u32 w;
if (sih->buscorerev == 0 || sih->buscorerev == 1) {
@@ -730,14 +719,14 @@ static void pcie_war_pci_setup(struct pcicore_info *pi)
}
/* ***** Functions called during driver state changes ***** */
-void pcicore_attach(void *pch, char *pvars, int state)
+void pcicore_attach(struct pcicore_info *pi, int state)
{
- struct pcicore_info *pi = pch;
struct si_pub *sih = pi->sih;
+ u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2);
/* Determine if this board needs override */
if (PCIE_ASPM(sih)) {
- if ((u32)getintvar(pvars, "boardflags2") & BFL2_PCIEWAR_OVR)
+ if (bfl2 & BFL2_PCIEWAR_OVR)
pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
else
pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
@@ -754,21 +743,17 @@ void pcicore_attach(void *pch, char *pvars, int state)
}
-void pcicore_hwup(void *pch)
+void pcicore_hwup(struct pcicore_info *pi)
{
- struct pcicore_info *pi = pch;
-
- if (!pi || !PCIE_PUB(pi->sih))
+ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID)
return;
pcie_war_pci_setup(pi);
}
-void pcicore_up(void *pch, int state)
+void pcicore_up(struct pcicore_info *pi, int state)
{
- struct pcicore_info *pi = pch;
-
- if (!pi || !PCIE_PUB(pi->sih))
+ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID)
return;
/* Restore L1 timer for better performance */
@@ -780,9 +765,8 @@ void pcicore_up(void *pch, int state)
/* When the device is going to enter D3 state
* (or the system is going to enter S3/S4 states)
*/
-void pcicore_sleep(void *pch)
+void pcicore_sleep(struct pcicore_info *pi)
{
- struct pcicore_info *pi = pch;
u32 w;
if (!pi || !PCIE_ASPM(pi->sih))
@@ -795,11 +779,9 @@ void pcicore_sleep(void *pch)
pi->pcie_pr42767 = false;
}
-void pcicore_down(void *pch, int state)
+void pcicore_down(struct pcicore_info *pi, int state)
{
- struct pcicore_info *pi = pch;
-
- if (!pi || !PCIE_PUB(pi->sih))
+ if (!pi || pi->sih->buscoretype != PCIE_CORE_ID)
return;
pcie_clkreq_upd(pi, state);
@@ -809,20 +791,12 @@ void pcicore_down(void *pch, int state)
}
/* precondition: current core is sii->buscoretype */
-void pcicore_fixcfg(void *pch, void *regs)
+static void pcicore_fixcfg(struct pcicore_info *pi, u16 __iomem *reg16)
{
- struct pcicore_info *pi = pch;
- struct si_info *sii = SI_INFO(pi->sih);
- struct sbpciregs *pciregs = regs;
- struct sbpcieregs *pcieregs = regs;
- u16 val16, *reg16 = NULL;
+ struct si_info *sii = (struct si_info *)(pi->sih);
+ u16 val16;
uint pciidx;
- /* check 'pi' is correct and fix it if not */
- if (sii->pub.buscoretype == PCIE_CORE_ID)
- reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
- else if (sii->pub.buscoretype == PCI_CORE_ID)
- reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
pciidx = ai_coreidx(&sii->pub);
val16 = R_REG(reg16);
if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16)pciidx) {
@@ -832,16 +806,27 @@ void pcicore_fixcfg(void *pch, void *regs)
}
}
+void
+pcicore_fixcfg_pci(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs)
+{
+ pcicore_fixcfg(pi, &pciregs->sprom[SRSH_PI_OFFSET]);
+}
+
+void pcicore_fixcfg_pcie(struct pcicore_info *pi,
+ struct sbpcieregs __iomem *pcieregs)
+{
+ pcicore_fixcfg(pi, &pcieregs->sprom[SRSH_PI_OFFSET]);
+}
+
/* precondition: current core is pci core */
-void pcicore_pci_setup(void *pch, void *regs)
+void
+pcicore_pci_setup(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs)
{
- struct pcicore_info *pi = pch;
- struct sbpciregs *pciregs = regs;
u32 w;
OR_REG(&pciregs->sbtopci2, SBTOPCI_PREF | SBTOPCI_BURST);
- if (SI_INFO(pi->sih)->pub.buscorerev >= 11) {
+ if (((struct si_info *)(pi->sih))->pub.buscorerev >= 11) {
OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI);
w = R_REG(&pciregs->clkrun);
W_REG(&pciregs->clkrun, w | PCI_CLKRUN_DSBL);
diff --git a/drivers/staging/brcm80211/brcmsmac/nicpci.h b/drivers/staging/brcm80211/brcmsmac/nicpci.h
index f71f842a2156..58aa80dc3329 100644
--- a/drivers/staging/brcm80211/brcmsmac/nicpci.h
+++ b/drivers/staging/brcm80211/brcmsmac/nicpci.h
@@ -58,28 +58,25 @@
/* bar0 + 12K accesses chipc core registers */
#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
-#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
+struct sbpciregs;
+struct sbpcieregs;
-/* Sonics to PCI translation types */
-#define SBTOPCI_PREF 0x4 /* prefetch enable */
-#define SBTOPCI_BURST 0x8 /* burst enable */
-#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
-
-/* PCI core index in SROM shadow area */
-#define SRSH_PI_OFFSET 0 /* first word */
-#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
-#define SRSH_PI_SHIFT 12 /* bit 15:12 */
-
-extern void *pcicore_init(struct si_pub *sih, void *pdev, void *regs);
-extern void pcicore_deinit(void *pch);
-extern void pcicore_attach(void *pch, char *pvars, int state);
-extern void pcicore_hwup(void *pch);
-extern void pcicore_up(void *pch, int state);
-extern void pcicore_sleep(void *pch);
-extern void pcicore_down(void *pch, int state);
-extern u8 pcicore_find_pci_capability(void *dev, u8 req_cap_id,
- unsigned char *buf, u32 *buflen);
-extern void pcicore_fixcfg(void *pch, void *regs);
-extern void pcicore_pci_setup(void *pch, void *regs);
+extern struct pcicore_info *pcicore_init(struct si_pub *sih,
+ struct pci_dev *pdev,
+ void __iomem *regs);
+extern void pcicore_deinit(struct pcicore_info *pch);
+extern void pcicore_attach(struct pcicore_info *pch, int state);
+extern void pcicore_hwup(struct pcicore_info *pch);
+extern void pcicore_up(struct pcicore_info *pch, int state);
+extern void pcicore_sleep(struct pcicore_info *pch);
+extern void pcicore_down(struct pcicore_info *pch, int state);
+extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
+ unsigned char *buf, u32 *buflen);
+extern void pcicore_fixcfg_pci(struct pcicore_info *pch,
+ struct sbpciregs __iomem *pciregs);
+extern void pcicore_fixcfg_pcie(struct pcicore_info *pch,
+ struct sbpcieregs __iomem *pciregs);
+extern void pcicore_pci_setup(struct pcicore_info *pch,
+ struct sbpciregs __iomem *pciregs);
#endif /* _BRCM_NICPCI_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/otp.c b/drivers/staging/brcm80211/brcmsmac/otp.c
index 4a70180eba5d..edf551561fd8 100644
--- a/drivers/staging/brcm80211/brcmsmac/otp.c
+++ b/drivers/staging/brcm80211/brcmsmac/otp.c
@@ -25,10 +25,14 @@
#define OTPS_GUP_MASK 0x00000f00
#define OTPS_GUP_SHIFT 8
-#define OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */
-#define OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */
-#define OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */
-#define OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */
+/* h/w subregion is programmed */
+#define OTPS_GUP_HW 0x00000100
+/* s/w subregion is programmed */
+#define OTPS_GUP_SW 0x00000200
+/* chipid/pkgopt subregion is programmed */
+#define OTPS_GUP_CI 0x00000400
+/* fuse subregion is programmed */
+#define OTPS_GUP_FUSE 0x00000800
/* Fields in otpprog in rev >= 21 */
#define OTPP_COL_MASK 0x000000ff
@@ -60,28 +64,21 @@
#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
-/* OTP common function type */
-typedef int (*otp_status_t) (void *oh);
-typedef int (*otp_size_t) (void *oh);
-typedef void *(*otp_init_t) (struct si_pub *sih);
-typedef u16(*otp_read_bit_t) (void *oh, chipcregs_t *cc, uint off);
-typedef int (*otp_read_region_t) (struct si_pub *sih, int region, u16 *data,
- uint *wlen);
-typedef int (*otp_nvread_t) (void *oh, char *data, uint *len);
+/* Fixed size subregions sizes in words */
+#define OTPGU_CI_SZ 2
+
+struct otpinfo;
/* OTP function struct */
struct otp_fn_s {
- otp_size_t size;
- otp_read_bit_t read_bit;
- otp_init_t init;
- otp_read_region_t read_region;
- otp_nvread_t nvread;
- otp_status_t status;
+ int (*init)(struct si_pub *sih, struct otpinfo *oi);
+ int (*read_region)(struct otpinfo *oi, int region, u16 *data,
+ uint *wlen);
};
struct otpinfo {
uint ccrev; /* chipc revision */
- struct otp_fn_s *fn; /* OTP functions */
+ const struct otp_fn_s *fn; /* OTP functions */
struct si_pub *sih; /* Saved sb handle */
/* IPX OTP section */
@@ -100,23 +97,6 @@ struct otpinfo {
int otpgu_base; /* offset to General Use Region */
};
-static struct otpinfo otpinfo;
-
-/*
- * IPX OTP Code
- *
- * Exported functions:
- * ipxotp_status()
- * ipxotp_size()
- * ipxotp_init()
- * ipxotp_read_bit()
- * ipxotp_read_region()
- * ipxotp_nvread()
- *
- */
-
-#define HWSW_RGN(rgn) (((rgn) == OTP_HW_RGN) ? "h/w" : "s/w")
-
/* OTP layout */
/* CC revs 21, 24 and 27 OTP General Use Region word offset */
#define REVA4_OTPGU_BASE 12
@@ -152,60 +132,15 @@ static struct otpinfo otpinfo;
#define OTP4315_SWREG_SZ 178 /* 178 bytes */
#define OTP_SZ_FU_144 (144/8) /* 144 bits */
-static int ipxotp_status(void *oh)
+static u16
+ipxotp_otpr(struct otpinfo *oi, struct chipcregs __iomem *cc, uint wn)
{
- struct otpinfo *oi = (struct otpinfo *) oh;
- return (int)(oi->status);
-}
-
-/* Return size in bytes */
-static int ipxotp_size(void *oh)
-{
- struct otpinfo *oi = (struct otpinfo *) oh;
- return (int)oi->wsize * 2;
-}
-
-static u16 ipxotp_otpr(void *oh, chipcregs_t *cc, uint wn)
-{
- struct otpinfo *oi;
-
- oi = (struct otpinfo *) oh;
-
return R_REG(&cc->sromotp[wn]);
}
-static u16 ipxotp_read_bit(void *oh, chipcregs_t *cc, uint off)
-{
- struct otpinfo *oi = (struct otpinfo *) oh;
- uint k, row, col;
- u32 otpp, st;
-
- row = off / oi->cols;
- col = off % oi->cols;
-
- otpp = OTPP_START_BUSY |
- ((OTPPOC_READ << OTPP_OC_SHIFT) & OTPP_OC_MASK) |
- ((row << OTPP_ROW_SHIFT) & OTPP_ROW_MASK) |
- ((col << OTPP_COL_SHIFT) & OTPP_COL_MASK);
- W_REG(&cc->otpprog, otpp);
-
- for (k = 0;
- ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
- && (k < OTPP_TRIES); k++)
- ;
- if (k >= OTPP_TRIES) {
- return 0xffff;
- }
- if (st & OTPP_READERR) {
- return 0xffff;
- }
- st = (st & OTPP_VALUE_MASK) >> OTPP_VALUE_SHIFT;
-
- return (int)st;
-}
-
-/* Calculate max HW/SW region byte size by subtracting fuse region and checksum size,
- * osizew is oi->wsize (OTP size - GU size) in words
+/*
+ * Calculate max HW/SW region byte size by subtracting fuse region
+ * and checksum size, osizew is oi->wsize (OTP size - GU size) in words
*/
static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
{
@@ -226,17 +161,23 @@ static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
return ret;
}
-static void _ipxotp_init(struct otpinfo *oi, chipcregs_t *cc)
+static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc)
{
uint k;
u32 otpp, st;
- /* record word offset of General Use Region for various chipcommon revs */
+ /*
+ * record word offset of General Use Region
+ * for various chipcommon revs
+ */
if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24
|| oi->sih->ccrev == 27) {
oi->otpgu_base = REVA4_OTPGU_BASE;
} else if (oi->sih->ccrev == 36) {
- /* OTP size greater than equal to 2KB (128 words), otpgu_base is similar to rev23 */
+ /*
+ * OTP size greater than equal to 2KB (128 words),
+ * otpgu_base is similar to rev23
+ */
if (oi->wsize >= 128)
oi->otpgu_base = REVB8_OTPGU_BASE;
else
@@ -254,9 +195,8 @@ static void _ipxotp_init(struct otpinfo *oi, chipcregs_t *cc)
((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY)
&& (k < OTPP_TRIES); k++)
;
- if (k >= OTPP_TRIES) {
+ if (k >= OTPP_TRIES)
return;
- }
/* Read OTP lock bits and subregion programmed indication bits */
oi->status = R_REG(&cc->otpstatus);
@@ -272,8 +212,9 @@ static void _ipxotp_init(struct otpinfo *oi, chipcregs_t *cc)
}
/*
- * h/w region base and fuse region limit are fixed to the top and
- * the bottom of the general use region. Everything else can be flexible.
+ * h/w region base and fuse region limit are fixed to
+ * the top and the bottom of the general use region.
+ * Everything else can be flexible.
*/
oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
oi->hwlim = oi->wsize;
@@ -297,28 +238,24 @@ static void _ipxotp_init(struct otpinfo *oi, chipcregs_t *cc)
oi->flim = oi->wsize;
}
-static void *ipxotp_init(struct si_pub *sih)
+static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
{
uint idx;
- chipcregs_t *cc;
- struct otpinfo *oi;
+ struct chipcregs __iomem *cc;
/* Make sure we're running IPX OTP */
if (!OTPTYPE_IPX(sih->ccrev))
- return NULL;
+ return -EBADE;
/* Make sure OTP is not disabled */
if (ai_is_otp_disabled(sih))
- return NULL;
-
- /* OTP is always powered */
- oi = &otpinfo;
+ return -EBADE;
/* Check for otp size */
switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
case 0:
/* Nothing there */
- return NULL;
+ return -EBADE;
case 1: /* 32x64 */
oi->rows = 32;
oi->cols = 64;
@@ -341,7 +278,7 @@ static void *ipxotp_init(struct si_pub *sih)
break;
default:
/* Don't know the geometry */
- return NULL;
+ return -EBADE;
}
/* Retrieve OTP region info */
@@ -352,14 +289,14 @@ static void *ipxotp_init(struct si_pub *sih)
ai_setcoreidx(sih, idx);
- return (void *)oi;
+ return 0;
}
-static int ipxotp_read_region(void *oh, int region, u16 *data, uint *wlen)
+static int
+ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
{
- struct otpinfo *oi = (struct otpinfo *) oh;
uint idx;
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint base, i, sz;
/* Validate region selection */
@@ -433,68 +370,23 @@ static int ipxotp_read_region(void *oh, int region, u16 *data, uint *wlen)
/* Read the data */
for (i = 0; i < sz; i++)
- data[i] = ipxotp_otpr(oh, cc, base + i);
+ data[i] = ipxotp_otpr(oi, cc, base + i);
ai_setcoreidx(oi->sih, idx);
*wlen = sz;
return 0;
}
-static int ipxotp_nvread(void *oh, char *data, uint *len)
-{
- return -ENOTSUPP;
-}
-
-static struct otp_fn_s ipxotp_fn = {
- (otp_size_t) ipxotp_size,
- (otp_read_bit_t) ipxotp_read_bit,
-
- (otp_init_t) ipxotp_init,
- (otp_read_region_t) ipxotp_read_region,
- (otp_nvread_t) ipxotp_nvread,
-
- (otp_status_t) ipxotp_status
+static const struct otp_fn_s ipxotp_fn = {
+ (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
+ (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
};
-/*
- * otp_status()
- * otp_size()
- * otp_read_bit()
- * otp_init()
- * otp_read_region()
- * otp_nvread()
- */
-
-int otp_status(void *oh)
+static int otp_init(struct si_pub *sih, struct otpinfo *oi)
{
- struct otpinfo *oi = (struct otpinfo *) oh;
- return oi->fn->status(oh);
-}
+ int ret;
-int otp_size(void *oh)
-{
- struct otpinfo *oi = (struct otpinfo *) oh;
-
- return oi->fn->size(oh);
-}
-
-u16 otp_read_bit(void *oh, uint offset)
-{
- struct otpinfo *oi = (struct otpinfo *) oh;
- uint idx = ai_coreidx(oi->sih);
- chipcregs_t *cc = ai_setcoreidx(oi->sih, SI_CC_IDX);
- u16 readBit = (u16) oi->fn->read_bit(oh, cc, offset);
- ai_setcoreidx(oi->sih, idx);
- return readBit;
-}
-
-void *otp_init(struct si_pub *sih)
-{
- struct otpinfo *oi;
- void *ret = NULL;
-
- oi = &otpinfo;
memset(oi, 0, sizeof(struct otpinfo));
oi->ccrev = sih->ccrev;
@@ -502,21 +394,20 @@ void *otp_init(struct si_pub *sih)
if (OTPTYPE_IPX(oi->ccrev))
oi->fn = &ipxotp_fn;
- if (oi->fn == NULL) {
- return NULL;
- }
+ if (oi->fn == NULL)
+ return -EBADE;
oi->sih = sih;
- ret = (oi->fn->init) (sih);
+ ret = (oi->fn->init) (sih, oi);
return ret;
}
int
-otp_read_region(struct si_pub *sih, int region, u16 *data,
- uint *wlen) {
- void *oh;
+otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
+ struct otpinfo otpinfo;
+ struct otpinfo *oi = &otpinfo;
int err = 0;
if (ai_is_otp_disabled(sih)) {
@@ -524,22 +415,12 @@ otp_read_region(struct si_pub *sih, int region, u16 *data,
goto out;
}
- oh = otp_init(sih);
- if (oh == NULL) {
- err = -EBADE;
+ err = otp_init(sih, oi);
+ if (err)
goto out;
- }
- err = (((struct otpinfo *) oh)->fn->read_region)
- (oh, region, data, wlen);
+ err = ((oi)->fn->read_region)(oi, region, data, wlen);
out:
return err;
}
-
-int otp_nvread(void *oh, char *data, uint *len)
-{
- struct otpinfo *oi = (struct otpinfo *) oh;
-
- return oi->fn->nvread(oh, data, len);
-}
diff --git a/drivers/staging/brcm80211/brcmsmac/otp.h b/drivers/staging/brcm80211/brcmsmac/otp.h
index f6d3a56acf1e..6b6d31cf9569 100644
--- a/drivers/staging/brcm80211/brcmsmac/otp.h
+++ b/drivers/staging/brcm80211/brcmsmac/otp.h
@@ -24,24 +24,13 @@
#define OTP_SW_RGN 2
#define OTP_CI_RGN 4
#define OTP_FUSE_RGN 8
-#define OTP_ALL_RGN 0xf /* From h/w region to end of OTP including checksum */
+/* From h/w region to end of OTP including checksum */
+#define OTP_ALL_RGN 0xf
/* OTP Size */
#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */
-/* Fixed size subregions sizes in words */
-#define OTPGU_CI_SZ 2
-
-/* OTP usage */
-#define OTP4325_FM_DISABLED_OFFSET 188
-
-/* Exported functions */
-extern int otp_status(void *oh);
-extern int otp_size(void *oh);
-extern u16 otp_read_bit(void *oh, uint offset);
-extern void *otp_init(struct si_pub *sih);
extern int otp_read_region(struct si_pub *sih, int region, u16 *data,
uint *wlen);
-extern int otp_nvread(void *oh, char *data, uint *len);
#endif /* _BRCM_OTP_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c
index 17012fbe9c97..a3149254cbcd 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_cmn.c
@@ -13,8 +13,9 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-
+#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/bitops.h>
#include <brcm_hw_ids.h>
#include <chipcommon.h>
@@ -27,14 +28,32 @@
#include "phy_lcn.h"
#include "phyreg_n.h"
-u32 phyhal_msg_level = PHYHAL_ERROR;
+#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \
+ (radioid == BCM2056_ID) || \
+ (radioid == BCM2057_ID))
+
+#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID)
+
+#define VALID_RADIO(pi, radioid) ( \
+ (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \
+ (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))
+
+/* basic mux operation - can be optimized on several architectures */
+#define MUX(pred, true, false) ((pred) ? (true) : (false))
+
+/* modulo inc/dec - assumes x E [0, bound - 1] */
+#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
+
+/* modulo inc/dec, bound = 2^k */
+#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
+#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
struct chan_info_basic {
u16 chan;
u16 freq;
};
-static struct chan_info_basic chan_info_all[] = {
+static const struct chan_info_basic chan_info_all[] = {
{1, 2412},
{2, 2417},
{3, 2422},
@@ -93,20 +112,6 @@ static struct chan_info_basic chan_info_all[] = {
{216, 50800}
};
-u16 ltrn_list[PHY_LTRN_LIST_LEN] = {
- 0x18f9, 0x0d01, 0x00e4, 0xdef4, 0x06f1, 0x0ffc,
- 0xfa27, 0x1dff, 0x10f0, 0x0918, 0xf20a, 0xe010,
- 0x1417, 0x1104, 0xf114, 0xf2fa, 0xf7db, 0xe2fc,
- 0xe1fb, 0x13ee, 0xff0d, 0xe91c, 0x171a, 0x0318,
- 0xda00, 0x03e8, 0x17e6, 0xe9e4, 0xfff3, 0x1312,
- 0xe105, 0xe204, 0xf725, 0xf206, 0xf1ec, 0x11fc,
- 0x14e9, 0xe0f0, 0xf2f6, 0x09e8, 0x1010, 0x1d01,
- 0xfad9, 0x0f04, 0x060f, 0xde0c, 0x001c, 0x0dff,
- 0x1807, 0xf61a, 0xe40e, 0x0f16, 0x05f9, 0x18ec,
- 0x0a1b, 0xff1e, 0x2600, 0xffe2, 0x0ae5, 0x1814,
- 0x0507, 0x0fea, 0xe4f2, 0xf6e6
-};
-
const u8 ofdm_rate_lookup[] = {
BRCM_RATE_48M,
@@ -119,66 +124,7 @@ const u8 ofdm_rate_lookup[] = {
BRCM_RATE_9M
};
-#define PHY_WREG_LIMIT 24
-
-static void wlc_set_phy_uninitted(struct brcms_phy *pi);
-static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi);
-static void wlc_phy_timercb_phycal(void *arg);
-
-static bool wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr,
- s8 *pwr_ant);
-
-static void wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi,
- uint delay);
-
-static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm);
-static void wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason,
- u8 ch);
-
-static void wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi,
- struct txpwr_limits *tp, chanspec_t);
-static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi);
-
-static s8 wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan,
- u32 band, u8 rate);
-static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band);
-static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi);
-static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi);
-
-char *phy_getvar(struct brcms_phy *pi, const char *name)
-{
- char *vars = pi->vars;
- char *s;
- int len;
-
- if (!name)
- return NULL;
-
- len = strlen(name);
- if (len == 0)
- return NULL;
-
- for (s = vars; s && *s;) {
- if ((memcmp(s, name, len) == 0) && (s[len] == '='))
- return &s[len + 1];
-
- while (*s++)
- ;
- }
-
- return NULL;
-}
-
-int phy_getintvar(struct brcms_phy *pi, const char *name)
-{
- char *val;
-
- val = PHY_GETVAR(pi, name);
- if (val == NULL)
- return 0;
-
- return simple_strtoul(val, NULL, 0);
-}
+#define PHY_WREG_LIMIT 24
void wlc_phyreg_enter(struct brcms_phy_pub *pih)
{
@@ -203,7 +149,7 @@ void wlc_radioreg_enter(struct brcms_phy_pub *pih)
void wlc_radioreg_exit(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
- volatile u16 dummy;
+ u16 dummy;
dummy = R_REG(&pi->regs->phyversion);
pi->phy_wreg = 0;
@@ -217,12 +163,10 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
if ((addr == RADIO_IDCODE))
return 0xffff;
- if (NORADIO_ENAB(pi->pubpi))
- return NORADIO_IDCODE & 0xffff;
-
switch (pi->pubpi.phy_type) {
case PHY_TYPE_N:
- CASECHECK(PHYTYPE, PHY_TYPE_N);
+ if (!CONF_HAS(PHYTYPE, PHY_TYPE_N))
+ break;
if (NREV_GE(pi->pubpi.phy_rev, 7))
addr |= RADIO_2057_READ_OFF;
else
@@ -230,7 +174,8 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
break;
case PHY_TYPE_LCN:
- CASECHECK(PHYTYPE, PHY_TYPE_LCN);
+ if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN))
+ break;
addr |= RADIO_2064_READ_OFF;
break;
@@ -262,9 +207,6 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
if ((D11REV_GE(pi->sh->corerev, 24)) ||
(D11REV_IS(pi->sh->corerev, 22)
&& (pi->pubpi.phy_type != PHY_TYPE_SSN))) {
@@ -276,11 +218,9 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
W_REG(&pi->regs->phy4wdatalo, val);
}
- if (pi->sh->bustype == PCI_BUS) {
- if (++pi->phy_wreg >= pi->phy_wreg_limit) {
- (void)R_REG(&pi->regs->maccontrol);
- pi->phy_wreg = 0;
- }
+ if (++pi->phy_wreg >= pi->phy_wreg_limit) {
+ (void)R_REG(&pi->regs->maccontrol);
+ pi->phy_wreg = 0;
}
}
@@ -288,9 +228,6 @@ static u32 read_radio_id(struct brcms_phy *pi)
{
u32 id;
- if (NORADIO_ENAB(pi->pubpi))
- return NORADIO_IDCODE;
-
if (D11REV_GE(pi->sh->corerev, 24)) {
u32 b0, b1, b2;
@@ -316,9 +253,6 @@ void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
u16 rval;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
rval = read_radio_reg(pi, addr);
write_radio_reg(pi, addr, (rval & val));
}
@@ -327,9 +261,6 @@ void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
u16 rval;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
rval = read_radio_reg(pi, addr);
write_radio_reg(pi, addr, (rval | val));
}
@@ -338,9 +269,6 @@ void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask)
{
u16 rval;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
rval = read_radio_reg(pi, addr);
write_radio_reg(pi, addr, (rval ^ mask));
}
@@ -349,9 +277,6 @@ void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
{
u16 rval;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
rval = read_radio_reg(pi, addr);
write_radio_reg(pi, addr, (rval & ~mask) | (val & mask));
}
@@ -363,7 +288,7 @@ void write_phy_channel_reg(struct brcms_phy *pi, uint val)
u16 read_phy_reg(struct brcms_phy *pi, u16 addr)
{
- d11regs_t *regs;
+ struct d11regs __iomem *regs;
regs = pi->regs;
@@ -375,30 +300,27 @@ u16 read_phy_reg(struct brcms_phy *pi, u16 addr)
void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
- d11regs_t *regs;
+ struct d11regs __iomem *regs;
regs = pi->regs;
-#ifdef __mips__
+#ifdef CONFIG_BCM47XX
W_REG_FLUSH(&regs->phyregaddr, addr);
W_REG(&regs->phyregdata, val);
if (addr == 0x72)
(void)R_REG(&regs->phyregdata);
#else
- W_REG((u32 *)(&regs->phyregaddr),
- addr | (val << 16));
- if (pi->sh->bustype == PCI_BUS) {
- if (++pi->phy_wreg >= pi->phy_wreg_limit) {
- pi->phy_wreg = 0;
- (void)R_REG(&regs->phyversion);
- }
+ W_REG((u32 __iomem *)(&regs->phyregaddr), addr | (val << 16));
+ if (++pi->phy_wreg >= pi->phy_wreg_limit) {
+ pi->phy_wreg = 0;
+ (void)R_REG(&regs->phyversion);
}
#endif
}
void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
- d11regs_t *regs;
+ struct d11regs __iomem *regs;
regs = pi->regs;
@@ -410,7 +332,7 @@ void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
{
- d11regs_t *regs;
+ struct d11regs __iomem *regs;
regs = pi->regs;
@@ -422,7 +344,7 @@ void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val)
void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val)
{
- d11regs_t *regs;
+ struct d11regs __iomem *regs;
regs = pi->regs;
@@ -464,9 +386,8 @@ static void wlc_set_phy_uninitted(struct brcms_phy *pi)
}
pi->radiopwr = 0xffff;
for (i = 0; i < STATIC_NUM_RF; i++) {
- for (j = 0; j < STATIC_NUM_BB; j++) {
+ for (j = 0; j < STATIC_NUM_BB; j++)
pi->stats_11b_txpower[i][j] = -1;
- }
}
}
@@ -475,9 +396,8 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
struct shared_phy *sh;
sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC);
- if (sh == NULL) {
+ if (sh == NULL)
return NULL;
- }
sh->sih = shp->sih;
sh->physhim = shp->physhim;
@@ -495,7 +415,6 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
sh->boardvendor = shp->boardvendor;
sh->boardflags = shp->boardflags;
sh->boardflags2 = shp->boardflags2;
- sh->bustype = shp->bustype;
sh->buscorerev = shp->buscorerev;
sh->fast_timer = PHY_SW_TIMER_FAST;
@@ -507,9 +426,40 @@ struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp)
return sh;
}
+static void wlc_phy_timercb_phycal(struct brcms_phy *pi)
+{
+ uint delay = 5;
+
+ if (PHY_PERICAL_MPHASE_PENDING(pi)) {
+ if (!pi->sh->up) {
+ wlc_phy_cal_perical_mphase_reset(pi);
+ return;
+ }
+
+ if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
+
+ delay = 1000;
+ wlc_phy_cal_perical_mphase_restart(pi);
+ } else
+ wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
+ wlapi_add_timer(pi->phycal_timer, delay, 0);
+ return;
+ }
+
+}
+
+static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
+{
+ u32 ver;
+
+ ver = read_radio_id(pi);
+
+ return ver;
+}
+
struct brcms_phy_pub *
-wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
- char *vars, struct wiphy *wiphy)
+wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs,
+ int bandtype, struct wiphy *wiphy)
{
struct brcms_phy *pi;
u32 sflags = 0;
@@ -522,42 +472,35 @@ wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
else
sflags = ai_core_sflags(sh->sih, 0, 0);
- if (BAND_5G(bandtype)) {
- if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) {
+ if (bandtype == BRCM_BAND_5G) {
+ if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0)
return NULL;
- }
}
pi = sh->phy_head;
if ((sflags & SISF_DB_PHY) && pi) {
-
wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
pi->refcnt++;
return &pi->pubpi_ro;
}
pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC);
- if (pi == NULL) {
+ if (pi == NULL)
return NULL;
- }
pi->wiphy = wiphy;
- pi->regs = (d11regs_t *) regs;
+ pi->regs = regs;
pi->sh = sh;
pi->phy_init_por = true;
pi->phy_wreg_limit = PHY_WREG_LIMIT;
- pi->vars = vars;
-
pi->txpwr_percent = 100;
pi->do_initcal = true;
pi->phycal_tempdelta = 0;
- if (BAND_2G(bandtype) && (sflags & SISF_2G_PHY)) {
-
+ if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY))
pi->pubpi.coreflags = SICF_GMODE;
- }
wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags);
phyversion = R_REG(&pi->regs->phyversion);
@@ -572,28 +515,26 @@ wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
pi->pubpi.phy_corenum = PHY_CORE_NUM_2;
pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT;
- if (!VALID_PHYTYPE(pi->pubpi.phy_type)) {
+ if (!pi->pubpi.phy_type == PHY_TYPE_N &&
+ !pi->pubpi.phy_type == PHY_TYPE_LCN)
goto err;
- }
- if (BAND_5G(bandtype)) {
- if (!ISNPHY(pi)) {
- goto err;
- }
- } else {
- if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
+
+ if (bandtype == BRCM_BAND_5G) {
+ if (!ISNPHY(pi))
goto err;
- }
+ } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) {
+ goto err;
}
wlc_phy_anacore((struct brcms_phy_pub *) pi, ON);
idcode = wlc_phy_get_radio_ver(pi);
pi->pubpi.radioid =
- (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
+ (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT;
pi->pubpi.radiorev =
- (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
+ (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT;
pi->pubpi.radiover =
- (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
+ (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT;
if (!VALID_RADIO(pi, pi->pubpi.radioid))
goto err;
@@ -602,8 +543,8 @@ wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
wlc_set_phy_uninitted(pi);
pi->bw = WL_CHANSPEC_BW_20;
- pi->radio_chanspec =
- BAND_2G(bandtype) ? CH20MHZ_CHSPEC(1) : CH20MHZ_CHSPEC(36);
+ pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ?
+ ch20mhz_chspec(1) : ch20mhz_chspec(36);
pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY;
pi->rxiq_antsel = ANT_RX_DIV_DEF;
@@ -625,7 +566,7 @@ wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
pi->phy_txcore_enable_temp =
- PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
+ PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP;
pi->phy_tempsense_offset = 0;
pi->phy_txcore_heatedup = false;
@@ -648,11 +589,10 @@ wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
if (ISNPHY(pi)) {
pi->phycal_timer = wlapi_init_timer(pi->sh->physhim,
- wlc_phy_timercb_phycal,
- pi, "phycal");
- if (!pi->phycal_timer) {
+ wlc_phy_timercb_phycal,
+ pi, "phycal");
+ if (!pi->phycal_timer)
goto err;
- }
if (!wlc_phy_attach_nphy(pi))
goto err;
@@ -661,21 +601,17 @@ wlc_phy_attach(struct shared_phy *sh, void *regs, int bandtype,
if (!wlc_phy_attach_lcnphy(pi))
goto err;
- } else {
-
}
pi->refcnt++;
pi->next = pi->sh->phy_head;
sh->phy_head = pi;
- pi->vars = (char *)&pi->vars;
-
memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub));
return &pi->pubpi_ro;
- err:
+err:
kfree(pi);
return NULL;
}
@@ -685,12 +621,11 @@ void wlc_phy_detach(struct brcms_phy_pub *pih)
struct brcms_phy *pi = (struct brcms_phy *) pih;
if (pih) {
- if (--pi->refcnt) {
+ if (--pi->refcnt)
return;
- }
if (pi->phycal_timer) {
- wlapi_free_timer(pi->sh->physhim, pi->phycal_timer);
+ wlapi_free_timer(pi->phycal_timer);
pi->phycal_timer = NULL;
}
@@ -700,7 +635,7 @@ void wlc_phy_detach(struct brcms_phy_pub *pih)
pi->sh->phy_head->next = NULL;
if (pi->pi_fptr.detach)
- (pi->pi_fptr.detach) (pi);
+ (pi->pi_fptr.detach)(pi);
kfree(pi);
}
@@ -731,29 +666,6 @@ u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih)
return pi->pubpi.coreflags;
}
-static void wlc_phy_timercb_phycal(void *arg)
-{
- struct brcms_phy *pi = (struct brcms_phy *) arg;
- uint delay = 5;
-
- if (PHY_PERICAL_MPHASE_PENDING(pi)) {
- if (!pi->sh->up) {
- wlc_phy_cal_perical_mphase_reset(pi);
- return;
- }
-
- if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) {
-
- delay = 1000;
- wlc_phy_cal_perical_mphase_restart(pi);
- } else
- wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO);
- wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
- return;
- }
-
-}
-
void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
@@ -862,10 +774,10 @@ void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate)
pi->sh->up = newstate;
}
-void wlc_phy_init(struct brcms_phy_pub *pih, chanspec_t chanspec)
+void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec)
{
u32 mc;
- initfn_t phy_init = NULL;
+ void (*phy_init)(struct brcms_phy *) = NULL;
struct brcms_phy *pi = (struct brcms_phy *) pih;
if (pi->init_in_progress)
@@ -879,9 +791,8 @@ void wlc_phy_init(struct brcms_phy_pub *pih, chanspec_t chanspec)
if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init"))
return;
- if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
+ if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
- }
if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA),
"HW error SISF_FCLKA\n"))
@@ -889,9 +800,8 @@ void wlc_phy_init(struct brcms_phy_pub *pih, chanspec_t chanspec)
phy_init = pi->pi_fptr.init;
- if (phy_init == NULL) {
+ if (phy_init == NULL)
return;
- }
wlc_phy_anacore(pih, ON);
@@ -903,7 +813,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, chanspec_t chanspec)
wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON);
- (*phy_init) (pi);
+ (*phy_init)(pi);
pi->phy_init_por = false;
@@ -921,7 +831,7 @@ void wlc_phy_init(struct brcms_phy_pub *pih, chanspec_t chanspec)
void wlc_phy_cal_init(struct brcms_phy_pub *pih)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
- initfn_t cal_init = NULL;
+ void (*cal_init)(struct brcms_phy *) = NULL;
if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0,
"HW error: MAC enabled during phy cal\n"))
@@ -930,7 +840,7 @@ void wlc_phy_cal_init(struct brcms_phy_pub *pih)
if (!pi->initialized) {
cal_init = pi->pi_fptr.calinit;
if (cal_init)
- (*cal_init) (pi);
+ (*cal_init)(pi);
pi->initialized = true;
}
@@ -942,7 +852,7 @@ int wlc_phy_down(struct brcms_phy_pub *pih)
int callbacks = 0;
if (pi->phycal_timer
- && !wlapi_del_timer(pi->sh->physhim, pi->phycal_timer))
+ && !wlapi_del_timer(pi->phycal_timer))
callbacks++;
pi->nphy_iqcal_chanspec_2G = 0;
@@ -951,15 +861,6 @@ int wlc_phy_down(struct brcms_phy_pub *pih)
return callbacks;
}
-static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi)
-{
- u32 ver;
-
- ver = read_radio_id(pi);
-
- return ver;
-}
-
void
wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset,
u16 tblAddr, u16 tblDataHi, u16 tblDataLo)
@@ -990,11 +891,9 @@ void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val)
}
if (width == 32) {
-
write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16));
write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
} else {
-
write_phy_reg(pi, pi->tbl_data_lo, (u16) val);
}
}
@@ -1025,15 +924,12 @@ wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
}
if (tbl_width == 32) {
-
write_phy_reg(pi, tblDataHi,
(u16) (ptbl_32b[idx] >> 16));
write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]);
} else if (tbl_width == 16) {
-
write_phy_reg(pi, tblDataLo, ptbl_16b[idx]);
} else {
-
write_phy_reg(pi, tblDataLo, ptbl_8b[idx]);
}
}
@@ -1064,14 +960,11 @@ wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info,
}
if (tbl_width == 32) {
-
ptbl_32b[idx] = read_phy_reg(pi, tblDataLo);
ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16);
} else if (tbl_width == 16) {
-
ptbl_16b[idx] = read_phy_reg(pi, tblDataLo);
} else {
-
ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo);
}
}
@@ -1084,10 +977,9 @@ wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
uint i = 0;
do {
- if (radioregs[i].do_init) {
+ if (radioregs[i].do_init)
write_radio_reg(pi, radioregs[i].address,
(u16) radioregs[i].init);
- }
i++;
} while (radioregs[i].address != 0xffff);
@@ -1096,7 +988,8 @@ wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
}
uint
-wlc_phy_init_radio_regs(struct brcms_phy *pi, struct radio_regs *radioregs,
+wlc_phy_init_radio_regs(struct brcms_phy *pi,
+ const struct radio_regs *radioregs,
u16 core_offset)
{
uint i = 0;
@@ -1131,8 +1024,8 @@ wlc_phy_init_radio_regs(struct brcms_phy *pi, struct radio_regs *radioregs,
void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
{
-#define DUMMY_PKT_LEN 20
- d11regs_t *regs = pi->regs;
+#define DUMMY_PKT_LEN 20
+ struct d11regs __iomem *regs = pi->regs;
int i, count;
u8 ofdmpkt[DUMMY_PKT_LEN] = {
0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00,
@@ -1156,9 +1049,8 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
W_REG(&regs->wepctl, 0);
W_REG(&regs->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0);
- if (ISNPHY(pi) || ISLCNPHY(pi)) {
+ if (ISNPHY(pi) || ISLCNPHY(pi))
W_REG(&regs->txe_phyctl1, 0x1A02);
- }
W_REG(&regs->txe_wm_0, 0);
W_REG(&regs->txe_wm_1, 0);
@@ -1185,16 +1077,14 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
i = 0;
count = ofdm ? 30 : 250;
while ((i++ < count)
- && (R_REG(&regs->txe_status) & (1 << 7))) {
+ && (R_REG(&regs->txe_status) & (1 << 7)))
udelay(10);
- }
i = 0;
while ((i++ < 10)
- && ((R_REG(&regs->txe_status) & (1 << 10)) == 0)) {
+ && ((R_REG(&regs->txe_status) & (1 << 10)) == 0))
udelay(10);
- }
i = 0;
@@ -1207,28 +1097,26 @@ void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on)
}
}
-void wlc_phy_hold_upd(struct brcms_phy_pub *pih, mbool id, bool set)
+void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
- if (set) {
+ if (set)
mboolset(pi->measure_hold, id);
- } else {
+ else
mboolclr(pi->measure_hold, id);
- }
return;
}
-void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, mbool flags)
+void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
- if (mute) {
+ if (mute)
mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE);
- } else {
+ else
mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE);
- }
if (!mute && (flags & PHY_MUTE_FOR_PREISM))
pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer;
@@ -1257,19 +1145,10 @@ static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi)
void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
-
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
- {
- uint mc;
-
- mc = R_REG(&pi->regs->maccontrol);
- }
+ (void)R_REG(&pi->regs->maccontrol);
if (ISNPHY(pi)) {
wlc_phy_switch_radio_nphy(pi, on);
-
} else if (ISLCNPHY(pi)) {
if (on) {
and_phy_reg(pi, 0x44c,
@@ -1311,26 +1190,25 @@ void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw)
pi->bw = bw;
}
-void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, chanspec_t newch)
+void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
pi->radio_chanspec = newch;
}
-chanspec_t wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
+u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
return pi->radio_chanspec;
}
-void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, chanspec_t chanspec)
+void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
u16 m_cur_channel;
- chansetfn_t chanspec_set = NULL;
-
+ void (*chanspec_set)(struct brcms_phy *, u16) = NULL;
m_cur_channel = CHSPEC_CHANNEL(chanspec);
if (CHSPEC_IS5G(chanspec))
m_cur_channel |= D11_CURCHANNEL_5G;
@@ -1340,7 +1218,7 @@ void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, chanspec_t chanspec)
chanspec_set = pi->pi_fptr.chanset;
if (chanspec_set)
- (*chanspec_set) (pi, chanspec);
+ (*chanspec_set)(pi, chanspec);
}
@@ -1360,17 +1238,16 @@ int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq)
return range;
}
-int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, chanspec_t chanspec)
+int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec)
{
int range = -1;
uint channel = CHSPEC_CHANNEL(chanspec);
uint freq = wlc_phy_channel2freq(channel);
- if (ISNPHY(pi)) {
+ if (ISNPHY(pi))
range = wlc_phy_get_chan_freq_range_nphy(pi, channel);
- } else if (ISLCNPHY(pi)) {
+ else if (ISLCNPHY(pi))
range = wlc_phy_chanspec_freq2bandrange_lpssn(freq);
- }
return range;
}
@@ -1396,13 +1273,13 @@ int wlc_phy_channel2freq(uint channel)
void
wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
- chanvec_t *channels)
+ struct brcms_chanvec *channels)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
uint i;
uint channel;
- memset(channels, 0, sizeof(chanvec_t));
+ memset(channels, 0, sizeof(struct brcms_chanvec));
for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
channel = chan_info_all[i].chan;
@@ -1417,17 +1294,17 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
}
}
-chanspec_t wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
+u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
uint i;
uint channel;
- chanspec_t chspec;
+ u16 chspec;
for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
channel = chan_info_all[i].chan;
- if (ISNPHY(pi) && IS40MHZ(pi)) {
+ if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) {
uint j;
for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) {
@@ -1439,16 +1316,15 @@ chanspec_t wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
if (j == ARRAY_SIZE(chan_info_all))
continue;
- channel = UPPER_20_SB(channel);
- chspec =
- channel | WL_CHANSPEC_BW_40 |
- WL_CHANSPEC_CTL_SB_LOWER;
+ channel = upper_20_sb(channel);
+ chspec = channel | WL_CHANSPEC_BW_40 |
+ WL_CHANSPEC_CTL_SB_LOWER;
if (band == BRCM_BAND_2G)
chspec |= WL_CHANSPEC_BAND_2G;
else
chspec |= WL_CHANSPEC_BAND_5G;
} else
- chspec = CH20MHZ_CHSPEC(channel);
+ chspec = ch20mhz_chspec(channel);
if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM)
&& (channel <= LAST_REF5_CHANNUM))
@@ -1459,7 +1335,7 @@ chanspec_t wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band)
return chspec;
}
- return (chanspec_t) INVCHANSPEC;
+ return (u16) INVCHANSPEC;
}
int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override)
@@ -1528,7 +1404,7 @@ int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
int i;
if (qdbm > 127)
- return 5;
+ return -EINVAL;
for (i = 0; i < TXP_NUM_RATES; i++)
pi->tx_user_target[i] = (u8) qdbm;
@@ -1539,10 +1415,8 @@ int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override)
if (!SCAN_INPROG_PHY(pi)) {
bool suspend;
- suspend =
- (0 ==
- (R_REG(&pi->regs->maccontrol) &
- MCTL_EN_MAC));
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) &
+ MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
@@ -1584,9 +1458,8 @@ wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr,
txp_rate_idx = TXP_FIRST_OFDM;
for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) {
- if (channel == chan_info_all[i].chan) {
+ if (channel == chan_info_all[i].chan)
break;
- }
}
if (pi->hwtxpwr) {
@@ -1620,7 +1493,8 @@ wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan,
pactrl = 0;
max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES :
- ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1);
+ ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 +
+ 1) : (TXP_LAST_OFDM + 1);
for (rate = 0; rate < max_num_rate; rate++) {
@@ -1659,6 +1533,46 @@ u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi)
return pi->tx_power_max;
}
+static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)
+{
+ if (ISLCNPHY(pi))
+ return wlc_lcnphy_vbatsense(pi, 0);
+ else
+ return 0;
+}
+
+static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)
+{
+ if (ISLCNPHY(pi))
+ return wlc_lcnphy_tempsense_degree(pi, 0);
+ else
+ return 0;
+}
+
+static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
+{
+ u8 i;
+ s8 temp, vbat;
+
+ for (i = 0; i < TXP_NUM_RATES; i++)
+ pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
+
+ vbat = wlc_phy_env_measure_vbat(pi);
+ temp = wlc_phy_env_measure_temperature(pi);
+
+}
+
+static s8
+wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
+ u8 rate)
+{
+ s8 offset = 0;
+
+ if (!pi->user_txpwr_at_rfport)
+ return offset;
+ return offset;
+}
+
void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
{
u8 maxtxpwr, mintxpwr, rate, pactrl;
@@ -1669,17 +1583,17 @@ void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
u8 tx_pwr_max_rate_ind = 0;
u8 max_num_rate;
u8 start_rate = 0;
- chanspec_t chspec;
+ u16 chspec;
u32 band = CHSPEC2BAND(pi->radio_chanspec);
- initfn_t txpwr_recalc_fn = NULL;
+ void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL;
chspec = pi->radio_chanspec;
if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE)
target_chan = CHSPEC_CHANNEL(chspec);
else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER)
- target_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
+ target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec));
else
- target_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
+ target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec));
pactrl = 0;
if (ISLCNPHY(pi)) {
@@ -1690,8 +1604,8 @@ void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
for (i = TXP_FIRST_SISO_MCS_20;
i <= TXP_LAST_SISO_MCS_20; i++) {
pi->tx_srom_max_rate_2g[i - 8] =
- pi->tx_srom_max_2g -
- ((offset_mcs & 0xf) * 2);
+ pi->tx_srom_max_2g -
+ ((offset_mcs & 0xf) * 2);
offset_mcs >>= 4;
}
} else {
@@ -1699,19 +1613,16 @@ void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
for (i = TXP_FIRST_SISO_MCS_20;
i <= TXP_LAST_SISO_MCS_20; i++) {
pi->tx_srom_max_rate_2g[i - 8] =
- pi->tx_srom_max_2g -
- ((offset_mcs & 0xf) * 2);
+ pi->tx_srom_max_2g -
+ ((offset_mcs & 0xf) * 2);
offset_mcs >>= 4;
}
}
}
-#if WL11N
+
max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) :
((ISLCNPHY(pi)) ?
(TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1)));
-#else
- max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : (TXP_LAST_OFDM + 1));
-#endif
wlc_phy_upd_env_txpwr_rate_limits(pi, band);
@@ -1719,35 +1630,32 @@ void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
tx_pwr_target[rate] = pi->tx_user_target[rate];
- if (pi->user_txpwr_at_rfport) {
+ if (pi->user_txpwr_at_rfport)
tx_pwr_target[rate] +=
- wlc_user_txpwr_antport_to_rfport(pi, target_chan,
- band, rate);
- }
+ wlc_user_txpwr_antport_to_rfport(pi,
+ target_chan,
+ band,
+ rate);
- {
+ wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
+ target_chan,
+ &mintxpwr, &maxtxpwr, rate);
- wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi,
- target_chan,
- &mintxpwr, &maxtxpwr, rate);
+ maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
- maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]);
-
- maxtxpwr =
- (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
+ maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0;
- maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
+ maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0;
- maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
+ maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]);
- if (pi->txpwr_percent <= 100)
- maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
+ if (pi->txpwr_percent <= 100)
+ maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100;
- tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
- }
+ tx_pwr_target[rate] = max(maxtxpwr, mintxpwr);
tx_pwr_target[rate] =
- min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
+ min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]);
if (tx_pwr_target[rate] > tx_pwr_max)
tx_pwr_max_rate_ind = rate;
@@ -1764,23 +1672,22 @@ void wlc_phy_txpower_recalc_target(struct brcms_phy *pi)
pi->tx_power_target[rate] = tx_pwr_target[rate];
- if (!pi->hwpwrctrl || ISNPHY(pi)) {
+ if (!pi->hwpwrctrl || ISNPHY(pi))
pi->tx_power_offset[rate] =
- pi->tx_power_max - pi->tx_power_target[rate];
- } else {
+ pi->tx_power_max - pi->tx_power_target[rate];
+ else
pi->tx_power_offset[rate] =
- pi->tx_power_target[rate] - pi->tx_power_min;
- }
+ pi->tx_power_target[rate] - pi->tx_power_min;
}
txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc;
if (txpwr_recalc_fn)
- (*txpwr_recalc_fn) (pi);
+ (*txpwr_recalc_fn)(pi);
}
-void
+static void
wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
- chanspec_t chanspec)
+ u16 chanspec)
{
u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM];
u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL;
@@ -1815,7 +1722,7 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
txpwr_ptr1 = txpwr->mcs_40_siso;
txpwr_ptr2 = txpwr->ofdm_40_siso;
rate_start_index =
- WL_TX_POWER_OFDM40_SISO_FIRST;
+ WL_TX_POWER_OFDM40_SISO_FIRST;
break;
case 3:
@@ -1825,18 +1732,21 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
break;
}
- for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; rate2++) {
+ for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
+ rate2++) {
tmp_txpwr_limit[rate2] = 0;
tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
- txpwr_ptr1[rate2];
+ txpwr_ptr1[rate2];
}
- wlc_phy_mcs_to_ofdm_powers_nphy(tmp_txpwr_limit, 0,
- BRCMS_NUM_RATES_OFDM - 1, BRCMS_NUM_RATES_OFDM);
+ wlc_phy_mcs_to_ofdm_powers_nphy(
+ tmp_txpwr_limit, 0,
+ BRCMS_NUM_RATES_OFDM -
+ 1, BRCMS_NUM_RATES_OFDM);
for (rate1 = rate_start_index, rate2 = 0;
rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++)
pi->txpwr_limit[rate1] =
- min(txpwr_ptr2[rate2],
- tmp_txpwr_limit[rate2]);
+ min(txpwr_ptr2[rate2],
+ tmp_txpwr_limit[rate2]);
}
for (k = 0; k < 4; k++) {
@@ -1866,19 +1776,22 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST;
break;
}
- for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; rate2++) {
+ for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM;
+ rate2++) {
tmp_txpwr_limit[rate2] = 0;
tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] =
- txpwr_ptr1[rate2];
+ txpwr_ptr1[rate2];
}
- wlc_phy_ofdm_to_mcs_powers_nphy(tmp_txpwr_limit, 0,
- BRCMS_NUM_RATES_OFDM - 1, BRCMS_NUM_RATES_OFDM);
+ wlc_phy_ofdm_to_mcs_powers_nphy(
+ tmp_txpwr_limit, 0,
+ BRCMS_NUM_RATES_OFDM -
+ 1, BRCMS_NUM_RATES_OFDM);
for (rate1 = rate_start_index, rate2 = 0;
rate2 < BRCMS_NUM_RATES_MCS_1_STREAM;
rate1++, rate2++)
pi->txpwr_limit[rate1] =
- min(txpwr_ptr2[rate2],
- tmp_txpwr_limit[rate2]);
+ min(txpwr_ptr2[rate2],
+ tmp_txpwr_limit[rate2]);
}
for (k = 0; k < 2; k++) {
@@ -1922,10 +1835,10 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr,
pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32;
pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] =
- min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
- pi->txpwr_limit[WL_TX_POWER_MCS_32]);
+ min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST],
+ pi->txpwr_limit[WL_TX_POWER_MCS_32]);
pi->txpwr_limit[WL_TX_POWER_MCS_32] =
- pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
+ pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST];
}
}
@@ -1975,7 +1888,7 @@ void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end)
void
wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr,
- chanspec_t chanspec)
+ u16 chanspec)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
@@ -2016,9 +1929,8 @@ void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt)
void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
{
int j;
- if (ISNPHY(pi)) {
+ if (ISNPHY(pi))
return;
- }
if (!pi->sh->clk)
return;
@@ -2040,9 +1952,9 @@ void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
const u8 ucode_ofdm_rates[] = {
0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c
};
- offset = wlapi_bmac_rate_shm_offset(pi->sh->physhim,
- ucode_ofdm_rates[j -
- TXP_FIRST_OFDM]);
+ offset = wlapi_bmac_rate_shm_offset(
+ pi->sh->physhim,
+ ucode_ofdm_rates[j - TXP_FIRST_OFDM]);
wlapi_bmac_write_shm(pi->sh->physhim, offset + 6,
pi->tx_power_offset[j]);
wlapi_bmac_write_shm(pi->sh->physhim, offset + 14,
@@ -2056,11 +1968,11 @@ void wlc_phy_txpower_update_shm(struct brcms_phy *pi)
for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++)
pi->tx_power_offset[i] =
- (u8) roundup(pi->tx_power_offset[i], 8);
+ (u8) roundup(pi->tx_power_offset[i], 8);
wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET,
- (u16) ((pi->
- tx_power_offset[TXP_FIRST_OFDM]
- + 7) >> 3));
+ (u16)
+ ((pi->tx_power_offset[TXP_FIRST_OFDM]
+ + 7) >> 3));
}
}
@@ -2068,48 +1980,38 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
- if (ISNPHY(pi)) {
+ if (ISNPHY(pi))
return pi->nphy_txpwrctrl;
- } else {
+ else
return pi->hwpwrctrl;
- }
}
void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl)
{
struct brcms_phy *pi = (struct brcms_phy *) ppi;
- bool cur_hwpwrctrl = pi->hwpwrctrl;
bool suspend;
- if (!pi->hwpwrctrl_capable) {
+ if (!pi->hwpwrctrl_capable)
return;
- }
pi->hwpwrctrl = hwpwrctrl;
pi->nphy_txpwrctrl = hwpwrctrl;
pi->txpwrctrl = hwpwrctrl;
if (ISNPHY(pi)) {
- suspend =
- (0 ==
- (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
- if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
wlc_phy_txpwr_fixpower_nphy(pi);
- } else {
-
+ else
mod_phy_reg(pi, 0x1e7, (0x7f << 0),
pi->saved_txpwr_idx);
- }
if (!suspend)
wlapi_enable_mac(pi->sh->physhim);
- } else if (hwpwrctrl != cur_hwpwrctrl) {
-
- return;
}
}
@@ -2125,8 +2027,6 @@ void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi)
}
}
-static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi);
-
static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
{
s16 tx0_status, tx1_status;
@@ -2137,42 +2037,31 @@ static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi)
estPower1 = read_phy_reg(pi, 0x118);
estPower2 = read_phy_reg(pi, 0x119);
- if ((estPower1 & (0x1 << 8))
- == (0x1 << 8)) {
- pwr0 = (u8) (estPower1 & (0xff << 0))
- >> 0;
- } else {
+ if ((estPower1 & (0x1 << 8)) == (0x1 << 8))
+ pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0;
+ else
pwr0 = 0x80;
- }
- if ((estPower2 & (0x1 << 8))
- == (0x1 << 8)) {
- pwr1 = (u8) (estPower2 & (0xff << 0))
- >> 0;
- } else {
+ if ((estPower2 & (0x1 << 8)) == (0x1 << 8))
+ pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0;
+ else
pwr1 = 0x80;
- }
tx0_status = read_phy_reg(pi, 0x1ed);
tx1_status = read_phy_reg(pi, 0x1ee);
- if ((tx0_status & (0x1 << 15))
- == (0x1 << 15)) {
- adj_pwr0 = (u8) (tx0_status & (0xff << 0))
- >> 0;
- } else {
+ if ((tx0_status & (0x1 << 15)) == (0x1 << 15))
+ adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0;
+ else
adj_pwr0 = 0x80;
- }
- if ((tx1_status & (0x1 << 15))
- == (0x1 << 15)) {
- adj_pwr1 = (u8) (tx1_status & (0xff << 0))
- >> 0;
- } else {
+ if ((tx1_status & (0x1 << 15)) == (0x1 << 15))
+ adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0;
+ else
adj_pwr1 = 0x80;
- }
- est_pwr =
- (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | adj_pwr1);
+ est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) |
+ adj_pwr1);
+
return est_pwr;
}
@@ -2193,7 +2082,7 @@ wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
power->flags |= (WL_TX_POWER_F_MIMO);
if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
power->flags |=
- (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
+ (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW);
} else if (ISLCNPHY(pi)) {
power->rf_cores = 1;
power->flags |= (WL_TX_POWER_F_SISO);
@@ -2256,16 +2145,18 @@ wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power,
power->tx_power_max[1] = pi->tx_power_max;
power->tx_power_max_rate_ind[0] =
- pi->tx_power_max_rate_ind;
+ pi->tx_power_max_rate_ind;
power->tx_power_max_rate_ind[1] =
- pi->tx_power_max_rate_ind;
+ pi->tx_power_max_rate_ind;
if (wlc_phy_tpc_isenabled_lcnphy(pi))
power->flags |=
- (WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
+ (WL_TX_POWER_F_HW |
+ WL_TX_POWER_F_ENABLED);
else
power->flags &=
- ~(WL_TX_POWER_F_HW | WL_TX_POWER_F_ENABLED);
+ ~(WL_TX_POWER_F_HW |
+ WL_TX_POWER_F_ENABLED);
wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0],
(s8 *) &power->est_Pout_cck);
@@ -2304,16 +2195,13 @@ void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val)
BRCM_BAND_ALL);
}
- if (ISNPHY(pi)) {
-
+ if (ISNPHY(pi))
return;
- }
if (!pi->sh->clk)
return;
- suspend =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
@@ -2357,10 +2245,127 @@ wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant)
pwr_ant[i] = cmplx_pwr_dbm[i];
}
pi->nphy_noise_index =
- MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
+ MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
return true;
}
+static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
+{
+ if (!pi->phynoise_state)
+ return;
+
+ if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
+ if (pi->phynoise_chan_watchdog == channel) {
+ pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
+ noise_dbm;
+ pi->sh->phy_noise_index =
+ MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
+ }
+ pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
+ }
+
+ if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL)
+ pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
+
+}
+
+static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
+{
+ u32 cmplx_pwr[PHY_CORE_MAX];
+ s8 noise_dbm_ant[PHY_CORE_MAX];
+ u16 lo, hi;
+ u32 cmplx_pwr_tot = 0;
+ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
+ u8 idx, core;
+
+ memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
+ memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
+
+ for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2,
+ core++) {
+ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
+ hi = wlapi_bmac_read_shm(pi->sh->physhim,
+ M_PWRIND_MAP(idx + 1));
+ cmplx_pwr[core] = (hi << 16) + lo;
+ cmplx_pwr_tot += cmplx_pwr[core];
+ if (cmplx_pwr[core] == 0)
+ noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
+ else
+ cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
+ }
+
+ if (cmplx_pwr_tot != 0)
+ wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ pi->nphy_noise_win[core][pi->nphy_noise_index] =
+ noise_dbm_ant[core];
+
+ if (noise_dbm_ant[core] > noise_dbm)
+ noise_dbm = noise_dbm_ant[core];
+ }
+ pi->nphy_noise_index =
+ MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
+
+ return noise_dbm;
+
+}
+
+void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
+{
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u16 jssi_aux;
+ u8 channel = 0;
+ s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
+
+ if (ISLCNPHY(pi)) {
+ u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
+ u16 lo, hi;
+ s32 pwr_offset_dB, gain_dB;
+ u16 status_0, status_1;
+
+ jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
+ channel = jssi_aux & D11_CURCHANNEL_MAX;
+
+ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
+ hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
+ cmplx_pwr0 = (hi << 16) + lo;
+
+ lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
+ hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
+ cmplx_pwr1 = (hi << 16) + lo;
+ cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
+
+ status_0 = 0x44;
+ status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
+ if ((cmplx_pwr > 0 && cmplx_pwr < 500)
+ && ((status_1 & 0xc000) == 0x4000)) {
+
+ wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
+ pi->pubpi.phy_corenum);
+ pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
+ if (pwr_offset_dB > 127)
+ pwr_offset_dB -= 256;
+
+ noise_dbm += (s8) (pwr_offset_dB - 30);
+
+ gain_dB = (status_0 & 0x1ff);
+ noise_dbm -= (s8) (gain_dB);
+ } else {
+ noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
+ }
+ } else if (ISNPHY(pi)) {
+
+ jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
+ channel = jssi_aux & D11_CURCHANNEL_MAX;
+
+ noise_dbm = wlc_phy_noise_read_shmem(pi);
+ }
+
+ wlc_phy_noise_cb(pi, channel, noise_dbm);
+
+}
+
static void
wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
{
@@ -2369,20 +2374,13 @@ wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
bool sampling_in_progress = (pi->phynoise_state != 0);
bool wait_for_intr = true;
- if (NORADIO_ENAB(pi->pubpi)) {
- return;
- }
-
switch (reason) {
case PHY_NOISE_SAMPLE_MON:
-
pi->phynoise_chan_watchdog = ch;
pi->phynoise_state |= PHY_NOISE_STATE_MON;
-
break;
case PHY_NOISE_SAMPLE_EXTERNAL:
-
pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL;
break;
@@ -2398,15 +2396,13 @@ wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
if (pi->phy_fixed_noise) {
if (ISNPHY(pi)) {
pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] =
- PHY_NOISE_FIXED_VAL_NPHY;
+ PHY_NOISE_FIXED_VAL_NPHY;
pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] =
- PHY_NOISE_FIXED_VAL_NPHY;
+ PHY_NOISE_FIXED_VAL_NPHY;
pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index,
PHY_NOISE_WINDOW_SZ);
-
noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
} else {
-
noise_dbm = PHY_NOISE_FIXED_VAL;
}
@@ -2469,15 +2465,14 @@ wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
wlapi_enable_mac(pi->sh->physhim);
for (i = 0; i < pi->pubpi.phy_corenum; i++)
- cmplx_pwr[i] =
- (est[i].i_pwr +
- est[i].q_pwr) >> log_num_samps;
+ cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >>
+ log_num_samps;
wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
for (i = 0; i < pi->pubpi.phy_corenum; i++) {
pi->nphy_noise_win[i][pi->nphy_noise_index] =
- noise_dbm_ant[i];
+ noise_dbm_ant[i];
if (noise_dbm_ant[i] > noise_dbm)
noise_dbm = noise_dbm_ant[i];
@@ -2489,7 +2484,7 @@ wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch)
}
}
- done:
+done:
if (!wait_for_intr)
wlc_phy_noise_cb(pi, ch, noise_dbm);
@@ -2505,124 +2500,7 @@ void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih)
wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel);
}
-static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm)
-{
- if (!pi->phynoise_state)
- return;
-
- if (pi->phynoise_state & PHY_NOISE_STATE_MON) {
- if (pi->phynoise_chan_watchdog == channel) {
- pi->sh->phy_noise_window[pi->sh->phy_noise_index] =
- noise_dbm;
- pi->sh->phy_noise_index =
- MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ);
- }
- pi->phynoise_state &= ~PHY_NOISE_STATE_MON;
- }
-
- if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) {
- pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL;
- }
-
-}
-
-static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi)
-{
- u32 cmplx_pwr[PHY_CORE_MAX];
- s8 noise_dbm_ant[PHY_CORE_MAX];
- u16 lo, hi;
- u32 cmplx_pwr_tot = 0;
- s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
- u8 idx, core;
-
- memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr));
- memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant));
-
- for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, core++) {
- lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx));
- hi = wlapi_bmac_read_shm(pi->sh->physhim,
- M_PWRIND_MAP(idx + 1));
- cmplx_pwr[core] = (hi << 16) + lo;
- cmplx_pwr_tot += cmplx_pwr[core];
- if (cmplx_pwr[core] == 0) {
- noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY;
- } else
- cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE;
- }
-
- if (cmplx_pwr_tot != 0)
- wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant);
-
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- pi->nphy_noise_win[core][pi->nphy_noise_index] =
- noise_dbm_ant[core];
-
- if (noise_dbm_ant[core] > noise_dbm)
- noise_dbm = noise_dbm_ant[core];
- }
- pi->nphy_noise_index =
- MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ);
-
- return noise_dbm;
-
-}
-
-void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih)
-{
- struct brcms_phy *pi = (struct brcms_phy *) pih;
- u16 jssi_aux;
- u8 channel = 0;
- s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY;
-
- if (ISLCNPHY(pi)) {
- u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1;
- u16 lo, hi;
- s32 pwr_offset_dB, gain_dB;
- u16 status_0, status_1;
-
- jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
- channel = jssi_aux & D11_CURCHANNEL_MAX;
-
- lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0);
- hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1);
- cmplx_pwr0 = (hi << 16) + lo;
-
- lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2);
- hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3);
- cmplx_pwr1 = (hi << 16) + lo;
- cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6;
-
- status_0 = 0x44;
- status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0);
- if ((cmplx_pwr > 0 && cmplx_pwr < 500)
- && ((status_1 & 0xc000) == 0x4000)) {
-
- wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm,
- pi->pubpi.phy_corenum);
- pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF);
- if (pwr_offset_dB > 127)
- pwr_offset_dB -= 256;
-
- noise_dbm += (s8) (pwr_offset_dB - 30);
-
- gain_dB = (status_0 & 0x1ff);
- noise_dbm -= (s8) (gain_dB);
- } else {
- noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY;
- }
- } else if (ISNPHY(pi)) {
-
- jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX);
- channel = jssi_aux & D11_CURCHANNEL_MAX;
-
- noise_dbm = wlc_phy_noise_read_shmem(pi);
- }
-
- wlc_phy_noise_cb(pi, channel, noise_dbm);
-
-}
-
-s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
+static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = {
8,
8,
8,
@@ -2678,27 +2556,21 @@ void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core)
}
}
-void wlc_phy_rssi_compute(struct brcms_phy_pub *pih, void *ctx)
+int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
+ struct d11rxhdr *rxh)
{
- struct brcms_d11rxhdr *wlc_rxhdr = (struct brcms_d11rxhdr *) ctx;
- struct d11rxhdr *rxh = &wlc_rxhdr->rxhdr;
- int rssi = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_JSSI_MASK;
+ int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK;
uint radioid = pih->radioid;
struct brcms_phy *pi = (struct brcms_phy *) pih;
- if (NORADIO_ENAB(pi->pubpi)) {
- rssi = BRCMS_RSSI_INVALID;
- goto end;
- }
-
if ((pi->sh->corerev >= 11)
- && !(le16_to_cpu(rxh->RxStatus2) & RXS_PHYRXST_VALID)) {
+ && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) {
rssi = BRCMS_RSSI_INVALID;
goto end;
}
if (ISLCNPHY(pi)) {
- u8 gidx = (le16_to_cpu(rxh->PhyRxStatus_2) & 0xFC00) >> 10;
+ u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
if (rssi > 127)
@@ -2715,16 +2587,15 @@ void wlc_phy_rssi_compute(struct brcms_phy_pub *pih, void *ctx)
}
if (ISLCNPHY(pi)) {
-
if (rssi > 127)
rssi -= 256;
} else if (radioid == BCM2055_ID || radioid == BCM2056_ID
|| radioid == BCM2057_ID) {
- rssi = wlc_phy_rssi_compute_nphy(pi, wlc_rxhdr);
+ rssi = wlc_phy_rssi_compute_nphy(pi, rxh);
}
- end:
- wlc_rxhdr->rssi = (s8) rssi;
+end:
+ return rssi;
}
void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih)
@@ -2757,28 +2628,22 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih)
if (!pi->watchdog_override)
return;
- if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) {
+ if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)))
wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi,
PHY_NOISE_SAMPLE_MON,
CHSPEC_CHANNEL(pi->
radio_chanspec));
- }
- if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) {
+ if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5)
pi->phynoise_state = 0;
- }
if ((!pi->phycal_txpower) ||
((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) {
- if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) {
+ if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi))
pi->phycal_txpower = pi->sh->now;
- }
}
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
|| ASSOC_INPROG_PHY(pi)))
return;
@@ -2800,8 +2665,9 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih)
((pi->sh->now - pi->phy_lastcal) >=
pi->sh->glacial_timer)) {
if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi)))
- wlc_lcnphy_calib_modes(pi,
- LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
+ wlc_lcnphy_calib_modes(
+ pi,
+ LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
if (!
(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)
|| ASSOC_INPROG_PHY(pi)
@@ -2819,13 +2685,12 @@ void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi)
uint i;
uint k;
- for (i = 0; i < MA_WINDOW_SZ; i++) {
+ for (i = 0; i < MA_WINDOW_SZ; i++)
pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff);
- }
if (ISLCNPHY(pi)) {
for (i = 0; i < MA_WINDOW_SZ; i++)
pi->sh->phy_noise_window[i] =
- PHY_NOISE_FIXED_VAL_LCNPHY;
+ PHY_NOISE_FIXED_VAL_LCNPHY;
}
pi->sh->phy_noise_index = 0;
@@ -2848,72 +2713,9 @@ wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag)
*eps_real -= 0x2000;
}
-static const fixed AtanTbl[] = {
- 2949120,
- 1740967,
- 919879,
- 466945,
- 234379,
- 117304,
- 58666,
- 29335,
- 14668,
- 7334,
- 3667,
- 1833,
- 917,
- 458,
- 229,
- 115,
- 57,
- 29
-};
-
-void wlc_phy_cordic(fixed theta, cs32 *val)
-{
- fixed angle, valtmp;
- unsigned iter;
- int signx = 1;
- int signtheta;
-
- val[0].i = CORDIC_AG;
- val[0].q = 0;
- angle = 0;
-
- signtheta = (theta < 0) ? -1 : 1;
- theta =
- ((theta + FIXED(180) * signtheta) % FIXED(360)) -
- FIXED(180) * signtheta;
-
- if (FLOAT(theta) > 90) {
- theta -= FIXED(180);
- signx = -1;
- } else if (FLOAT(theta) < -90) {
- theta += FIXED(180);
- signx = -1;
- }
-
- for (iter = 0; iter < CORDIC_NI; iter++) {
- if (theta > angle) {
- valtmp = val[0].i - (val[0].q >> iter);
- val[0].q = (val[0].i >> iter) + val[0].q;
- val[0].i = valtmp;
- angle += AtanTbl[iter];
- } else {
- valtmp = val[0].i + (val[0].q >> iter);
- val[0].q = -(val[0].i >> iter) + val[0].q;
- val[0].i = valtmp;
- angle -= AtanTbl[iter];
- }
- }
-
- val[0].i = val[0].i * signx;
- val[0].q = val[0].q * signx;
-}
-
void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi)
{
- wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
+ wlapi_del_timer(pi->phycal_timer);
pi->cal_type_override = PHY_PERICAL_AUTO;
pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE;
@@ -2928,10 +2730,10 @@ wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay)
(pi->nphy_perical != PHY_PERICAL_MANUAL))
return;
- wlapi_del_timer(pi->sh->physhim, pi->phycal_timer);
+ wlapi_del_timer(pi->phycal_timer);
pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT;
- wlapi_add_timer(pi->sh->physhim, pi->phycal_timer, delay, 0);
+ wlapi_add_timer(pi->phycal_timer, delay, 0);
}
void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
@@ -2954,11 +2756,12 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
case PHY_PERICAL_PHYINIT:
if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
- if (PHY_PERICAL_MPHASE_PENDING(pi)) {
+ if (PHY_PERICAL_MPHASE_PENDING(pi))
wlc_phy_cal_perical_mphase_reset(pi);
- }
- wlc_phy_cal_perical_mphase_schedule(pi,
- PHY_PERICAL_INIT_DELAY);
+
+ wlc_phy_cal_perical_mphase_schedule(
+ pi,
+ PHY_PERICAL_INIT_DELAY);
}
break;
@@ -2966,17 +2769,16 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
case PHY_PERICAL_START_IBSS:
case PHY_PERICAL_UP_BSS:
if ((pi->nphy_perical == PHY_PERICAL_MPHASE) &&
- PHY_PERICAL_MPHASE_PENDING(pi)) {
+ PHY_PERICAL_MPHASE_PENDING(pi))
wlc_phy_cal_perical_mphase_reset(pi);
- }
pi->first_cal_after_assoc = true;
pi->cal_type_override = PHY_PERICAL_FULL;
- if (pi->phycal_tempdelta) {
+ if (pi->phycal_tempdelta)
pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi);
- }
+
wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL);
break;
@@ -2984,26 +2786,24 @@ void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason)
if (pi->phycal_tempdelta) {
nphy_currtemp = wlc_phy_tempsense_nphy(pi);
delta_temp =
- (nphy_currtemp > pi->nphy_lastcal_temp) ?
- nphy_currtemp - pi->nphy_lastcal_temp :
- pi->nphy_lastcal_temp - nphy_currtemp;
+ (nphy_currtemp > pi->nphy_lastcal_temp) ?
+ nphy_currtemp - pi->nphy_lastcal_temp :
+ pi->nphy_lastcal_temp - nphy_currtemp;
if ((delta_temp < (s16) pi->phycal_tempdelta) &&
(pi->nphy_txiqlocal_chanspec ==
- pi->radio_chanspec)) {
+ pi->radio_chanspec))
do_periodic_cal = false;
- } else {
+ else
pi->nphy_lastcal_temp = nphy_currtemp;
- }
}
if (do_periodic_cal) {
-
if (pi->nphy_perical == PHY_PERICAL_MPHASE) {
-
if (!PHY_PERICAL_MPHASE_PENDING(pi))
- wlc_phy_cal_perical_mphase_schedule(pi,
- PHY_PERICAL_WDOG_DELAY);
+ wlc_phy_cal_perical_mphase_schedule(
+ pi,
+ PHY_PERICAL_WDOG_DELAY);
} else if (pi->nphy_perical == PHY_PERICAL_SPHASE)
wlc_phy_cal_perical_nphy_run(pi,
PHY_PERICAL_AUTO);
@@ -3025,7 +2825,7 @@ u8 wlc_phy_nbits(s32 value)
s32 abs_val;
u8 nbits = 0;
- abs_val = ABS(value);
+ abs_val = abs(value);
while ((abs_val >> nbits) > 0)
nbits++;
@@ -3040,7 +2840,7 @@ void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
pi->sh->hw_phyrxchain = rxchain;
pi->sh->phytxchain = txchain;
pi->sh->phyrxchain = rxchain;
- pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
+ pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
}
void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
@@ -3049,10 +2849,10 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain)
pi->sh->phytxchain = txchain;
- if (ISNPHY(pi)) {
+ if (ISNPHY(pi))
wlc_phy_rxcore_setstate_nphy(pih, rxchain);
- }
- pi->pubpi.phy_corenum = (u8) PHY_BITSCNT(pi->sh->phyrxchain);
+
+ pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain);
}
void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain)
@@ -3095,17 +2895,17 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih)
return active_bitmap;
}
-s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, chanspec_t chanspec)
+s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec)
{
struct brcms_phy *pi = (struct brcms_phy *) pih;
u8 siso_mcs_id, cdd_mcs_id;
siso_mcs_id =
- (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
- TXP_FIRST_MCS_20_SISO;
+ (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO :
+ TXP_FIRST_MCS_20_SISO;
cdd_mcs_id =
- (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
- TXP_FIRST_MCS_20_CDD;
+ (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD :
+ TXP_FIRST_MCS_20_CDD;
if (pi->tx_power_target[siso_mcs_id] >
(pi->tx_power_target[cdd_mcs_id] + 12))
@@ -3133,12 +2933,13 @@ void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
}
ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, gpiocontrol), ~0x0,
- 0x0);
+ offsetof(struct chipcregs, gpiocontrol),
+ ~0x0, 0x0);
ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, gpioout), 0x40, 0x40);
+ offsetof(struct chipcregs, gpioout), 0x40,
+ 0x40);
ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, gpioouten), 0x40,
+ offsetof(struct chipcregs, gpioouten), 0x40,
0x40);
} else {
mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2);
@@ -3146,56 +2947,18 @@ void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode)
mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2);
ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, gpioout), 0x40, 0x00);
+ offsetof(struct chipcregs, gpioout), 0x40,
+ 0x00);
ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, gpioouten), 0x40, 0x0);
+ offsetof(struct chipcregs, gpioouten), 0x40,
+ 0x0);
ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, gpiocontrol), ~0x0,
- 0x40);
+ offsetof(struct chipcregs, gpiocontrol),
+ ~0x0, 0x40);
}
}
}
-static s8
-wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band,
- u8 rate)
-{
- s8 offset = 0;
-
- if (!pi->user_txpwr_at_rfport)
- return offset;
- return offset;
-}
-
-static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi)
-{
- if (ISLCNPHY(pi))
- return wlc_lcnphy_vbatsense(pi, 0);
- else
- return 0;
-}
-
-static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi)
-{
- if (ISLCNPHY(pi))
- return wlc_lcnphy_tempsense_degree(pi, 0);
- else
- return 0;
-}
-
-static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band)
-{
- u8 i;
- s8 temp, vbat;
-
- for (i = 0; i < TXP_NUM_RATES; i++)
- pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX;
-
- vbat = wlc_phy_env_measure_vbat(pi);
- temp = wlc_phy_env_measure_temperature(pi);
-
-}
-
void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc)
{
return;
@@ -3208,7 +2971,7 @@ wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset)
*ofdmoffset = 0;
}
-s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, chanspec_t chanspec)
+s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec)
{
return rssi;
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/staging/brcm80211/brcmsmac/phy/phy_hal.h
index e27d9e95a2dc..96e15163222b 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_hal.h
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_hal.h
@@ -103,6 +103,9 @@
#define BRCMS_RSSI_INVALID 0 /* invalid RSSI value */
+struct d11regs;
+struct phy_shim_info;
+
struct txpwr_limits {
u8 cck[BRCMS_NUM_RATES_CCK];
u8 ofdm[BRCMS_NUM_RATES_OFDM];
@@ -126,42 +129,44 @@ struct txpwr_limits {
struct tx_power {
u32 flags;
- chanspec_t chanspec; /* txpwr report for this channel */
- chanspec_t local_chanspec; /* channel on which we are associated */
- u8 local_max; /* local max according to the AP */
- u8 local_constraint; /* local constraint according to the AP */
- s8 antgain[2]; /* Ant gain for each band - from SROM */
- u8 rf_cores; /* count of RF Cores being reported */
- u8 est_Pout[4]; /* Latest tx power out estimate per RF chain */
- u8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain
- * without adjustment
- */
- u8 est_Pout_cck; /* Latest CCK tx power out estimate */
- u8 tx_power_max[4]; /* Maximum target power among all rates */
- u8 tx_power_max_rate_ind[4]; /* Index of the rate with the max target power */
- u8 user_limit[WL_TX_POWER_RATES]; /* User limit */
- u8 reg_limit[WL_TX_POWER_RATES]; /* Regulatory power limit */
- u8 board_limit[WL_TX_POWER_RATES]; /* Max power board can support (SROM) */
- u8 target[WL_TX_POWER_RATES]; /* Latest target power */
+ u16 chanspec; /* txpwr report for this channel */
+ u16 local_chanspec; /* channel on which we are associated */
+ u8 local_max; /* local max according to the AP */
+ u8 local_constraint; /* local constraint according to the AP */
+ s8 antgain[2]; /* Ant gain for each band - from SROM */
+ u8 rf_cores; /* count of RF Cores being reported */
+ u8 est_Pout[4]; /* Latest tx power out estimate per RF chain */
+ u8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain
+ * without adjustment */
+ u8 est_Pout_cck; /* Latest CCK tx power out estimate */
+ u8 tx_power_max[4]; /* Maximum target power among all rates */
+ /* Index of the rate with the max target power */
+ u8 tx_power_max_rate_ind[4];
+ /* User limit */
+ u8 user_limit[WL_TX_POWER_RATES];
+ /* Regulatory power limit */
+ u8 reg_limit[WL_TX_POWER_RATES];
+ /* Max power board can support (SROM) */
+ u8 board_limit[WL_TX_POWER_RATES];
+ /* Latest target power */
+ u8 target[WL_TX_POWER_RATES];
};
struct tx_inst_power {
- u8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */
- u8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */
+ u8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */
+ u8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */
};
-struct chanvec {
+struct brcms_chanvec {
u8 vec[MAXCHANNEL / NBBY];
};
struct shared_phy_params {
struct si_pub *sih;
- void *physhim;
+ struct phy_shim_info *physhim;
uint unit;
uint corerev;
- uint bustype;
uint buscorerev;
- char *vars;
u16 vid;
u16 did;
uint chip;
@@ -177,8 +182,9 @@ struct shared_phy_params {
extern struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp);
-extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh, void *regs,
- int bandtype, char *vars, struct wiphy *wiphy);
+extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh,
+ struct d11regs __iomem *regs,
+ int bandtype, struct wiphy *wiphy);
extern void wlc_phy_detach(struct brcms_phy_pub *ppi);
extern bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype,
@@ -189,7 +195,7 @@ extern u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih);
extern void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *ppi, bool newstate);
extern void wlc_phy_hw_state_upd(struct brcms_phy_pub *ppi, bool newstate);
-extern void wlc_phy_init(struct brcms_phy_pub *ppi, chanspec_t chanspec);
+extern void wlc_phy_init(struct brcms_phy_pub *ppi, u16 chanspec);
extern void wlc_phy_watchdog(struct brcms_phy_pub *ppi);
extern int wlc_phy_down(struct brcms_phy_pub *ppi);
extern u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih);
@@ -197,14 +203,15 @@ extern void wlc_phy_cal_init(struct brcms_phy_pub *ppi);
extern void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init);
extern void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi,
- chanspec_t chanspec);
-extern chanspec_t wlc_phy_chanspec_get(struct brcms_phy_pub *ppi);
+ u16 chanspec);
+extern u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi);
extern void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi,
- chanspec_t newch);
+ u16 newch);
extern u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi);
extern void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw);
-extern void wlc_phy_rssi_compute(struct brcms_phy_pub *pih, void *ctx);
+extern int wlc_phy_rssi_compute(struct brcms_phy_pub *pih,
+ struct d11rxhdr *rxh);
extern void wlc_phy_por_inform(struct brcms_phy_pub *ppi);
extern void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi);
extern bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi);
@@ -220,9 +227,9 @@ extern void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi);
extern void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi,
bool wide_filter);
extern void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band,
- chanvec_t *channels);
-extern chanspec_t wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi,
- uint band);
+ struct brcms_chanvec *channels);
+extern u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi,
+ uint band);
extern void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan,
u8 *_min_, u8 *_max_, int rate);
@@ -232,7 +239,7 @@ extern void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi,
uint band, s32 *, s32 *, u32 *);
extern void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi,
struct txpwr_limits *,
- chanspec_t chanspec);
+ u16 chanspec);
extern int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm,
bool *override);
extern int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm,
@@ -254,7 +261,7 @@ extern void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain,
u8 *rxchain);
extern u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih);
extern s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih,
- chanspec_t chanspec);
+ u16 chanspec);
extern void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val);
extern void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason);
@@ -264,8 +271,8 @@ extern void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi);
extern void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val);
extern void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi);
-extern void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, mbool id, bool val);
-extern void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, mbool flags);
+extern void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val);
+extern void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags);
extern void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type);
@@ -289,6 +296,6 @@ extern void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi);
extern const u8 *wlc_phy_get_ofdm_rate_lookup(void);
extern s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi,
- u8 mcs_offset);
+ u8 mcs_offset);
extern s8 wlc_phy_get_tx_power_offset(struct brcms_phy_pub *ppi, u8 tbl_offset);
-#endif /* _BRCM_PHY_HAL_H_ */
+#endif /* _BRCM_PHY_HAL_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_int.h b/drivers/staging/brcm80211/brcmsmac/phy/phy_int.h
index a01b01ccd9ff..bea85241a244 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_int.h
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_int.h
@@ -23,53 +23,26 @@
#define PHY_VERSION { 1, 82, 8, 0 }
-#define PHYHAL_ERROR 0x0001
-#define PHYHAL_TRACE 0x0002
-#define PHYHAL_INFORM 0x0004
-
-extern u32 phyhal_msg_level;
-
-#define PHY_INFORM_ON() (phyhal_msg_level & PHYHAL_INFORM)
-#define PHY_THERMAL_ON() (phyhal_msg_level & PHYHAL_THERMAL)
-#define PHY_CAL_ON() (phyhal_msg_level & PHYHAL_CAL)
-
-#ifdef BOARD_TYPE
-#define BOARDTYPE(_type) BOARD_TYPE
-#else
-#define BOARDTYPE(_type) _type
-#endif
-
#define LCNXN_BASEREV 16
+struct phy_shim_info;
+
struct brcms_phy_srom_fem {
- u8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */
- u8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */
- u8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */
- u8 triso; /* TR switch isolation */
- u8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */
+ /* TSSI positive slope, 1: positive, 0: negative */
+ u8 tssipos;
+ /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */
+ u8 extpagain;
+ /* support 32 combinations of different Pdet dynamic ranges */
+ u8 pdetrange;
+ /* TR switch isolation */
+ u8 triso;
+ /* antswctrl lookup table configuration: 32 possible choices */
+ u8 antswctrllut;
};
-typedef void (*initfn_t) (struct brcms_phy *);
-typedef void (*chansetfn_t) (struct brcms_phy *, chanspec_t);
-typedef int (*longtrnfn_t) (struct brcms_phy *, int);
-typedef void (*txiqccgetfn_t) (struct brcms_phy *, u16 *, u16 *);
-typedef void (*txiqccsetfn_t) (struct brcms_phy *, u16, u16);
-typedef u16(*txloccgetfn_t) (struct brcms_phy *);
-typedef void (*radioloftgetfn_t) (struct brcms_phy *, u8 *, u8 *, u8 *,
- u8 *);
-typedef s32(*rxsigpwrfn_t) (struct brcms_phy *, s32);
-typedef void (*detachfn_t) (struct brcms_phy *);
-
-#undef ISNPHY
-#undef ISLCNPHY
#define ISNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_N)
#define ISLCNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_LCN)
-#define ISPHY_11N_CAP(pi) (ISNPHY(pi) || ISLCNPHY(pi))
-
-#define IS20MHZ(pi) ((pi)->bw == WL_CHANSPEC_BW_20)
-#define IS40MHZ(pi) ((pi)->bw == WL_CHANSPEC_BW_40)
-
#define PHY_GET_RFATTN(rfgain) ((rfgain) & 0x0f)
#define PHY_GET_PADMIX(rfgain) (((rfgain) & 0x10) >> 4)
#define PHY_GET_RFGAINID(rfattn, padmix, width) ((rfattn) + ((padmix)*(width)))
@@ -203,7 +176,9 @@ typedef void (*detachfn_t) (struct brcms_phy *);
#define PHY_PERICAL_WDOG_DELAY 5
#define MPHASE_TXCAL_NUMCMDS 2
-#define PHY_PERICAL_MPHASE_PENDING(pi) (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_IDLE)
+
+#define PHY_PERICAL_MPHASE_PENDING(pi) \
+ (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_IDLE)
enum {
MPHASE_CAL_STATE_IDLE = 0,
@@ -248,47 +223,29 @@ enum phy_cal_mode {
#define CORDIC_AG 39797
#define CORDIC_NI 18
#define FIXED(X) ((s32)((X) << 16))
-#define FLOAT(X) (((X) >= 0) ? ((((X) >> 15) + 1) >> 1) : -((((-(X)) >> 15) + 1) >> 1))
+
+#define FLOAT(X) \
+ (((X) >= 0) ? ((((X) >> 15) + 1) >> 1) : -((((-(X)) >> 15) + 1) >> 1))
#define PHY_CHAIN_TX_DISABLE_TEMP 115
#define PHY_HYSTERESIS_DELTATEMP 5
-#define PHY_BITSCNT(x) brcmu_bitcount((u8 *)&(x), sizeof(u8))
-
-#define MOD_PHY_REG(pi, phy_type, reg_name, field, value) \
- mod_phy_reg(pi, phy_type##_##reg_name, phy_type##_##reg_name##_##field##_MASK, \
- (value) << phy_type##_##reg_name##_##field##_##SHIFT);
-#define READ_PHY_REG(pi, phy_type, reg_name, field) \
- ((read_phy_reg(pi, phy_type##_##reg_name) & phy_type##_##reg_name##_##field##_##MASK)\
- >> phy_type##_##reg_name##_##field##_##SHIFT)
+#define SCAN_INPROG_PHY(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN))
-#define VALID_PHYTYPE(phytype) (((uint)phytype == PHY_TYPE_N) || \
- ((uint)phytype == PHY_TYPE_LCN))
+#define PLT_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_PLT))
-#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || (radioid == BCM2056_ID) || \
- (radioid == BCM2057_ID))
-#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID)
+#define ASSOC_INPROG_PHY(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_ASSOC))
-#define VALID_RADIO(pi, radioid) (\
- (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \
- (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false))
+#define SCAN_RM_IN_PROGRESS(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN | PHY_HOLD_FOR_RM))
-#define SCAN_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN))
-#define RM_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_RM))
-#define PLT_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_PLT))
-#define ASSOC_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_ASSOC))
-#define SCAN_RM_IN_PROGRESS(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN | PHY_HOLD_FOR_RM))
-#define PHY_MUTED(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_MUTE))
-#define PUB_NOT_ASSOC(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_NOT_ASSOC))
+#define PHY_MUTED(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_MUTE))
-#if defined(EXT_CBALL)
-#define NORADIO_ENAB(pub) ((pub).radioid == NORADIO_ID)
-#else
-#define NORADIO_ENAB(pub) 0
-#endif
-
-#define PHY_LTRN_LIST_LEN 64
-extern u16 ltrn_list[PHY_LTRN_LIST_LEN];
+#define PUB_NOT_ASSOC(pi) \
+ (mboolisset(pi->measure_hold, PHY_HOLD_FOR_NOT_ASSOC))
struct phy_table_info {
uint table;
@@ -532,7 +489,7 @@ struct shared_phy {
struct brcms_phy *phy_head;
uint unit;
struct si_pub *sih;
- void *physhim;
+ struct phy_shim_info *physhim;
uint corerev;
u32 machwcap;
bool up;
@@ -549,7 +506,6 @@ struct shared_phy {
uint boardvendor;
u32 boardflags;
u32 boardflags2;
- uint bustype;
uint buscorerev;
uint fast_timer;
uint slow_timer;
@@ -579,41 +535,39 @@ struct brcms_phy_pub {
};
struct phy_func_ptr {
- initfn_t init;
- initfn_t calinit;
- chansetfn_t chanset;
- initfn_t txpwrrecalc;
- longtrnfn_t longtrn;
- txiqccgetfn_t txiqccget;
- txiqccsetfn_t txiqccset;
- txloccgetfn_t txloccget;
- radioloftgetfn_t radioloftget;
- initfn_t carrsuppr;
- rxsigpwrfn_t rxsigpwr;
- detachfn_t detach;
+ void (*init)(struct brcms_phy *);
+ void (*calinit)(struct brcms_phy *);
+ void (*chanset)(struct brcms_phy *, u16 chanspec);
+ void (*txpwrrecalc)(struct brcms_phy *);
+ int (*longtrn)(struct brcms_phy *, int);
+ void (*txiqccget)(struct brcms_phy *, u16 *, u16 *);
+ void (*txiqccset)(struct brcms_phy *, u16, u16);
+ u16 (*txloccget)(struct brcms_phy *);
+ void (*radioloftget)(struct brcms_phy *, u8 *, u8 *, u8 *, u8 *);
+ void (*carrsuppr)(struct brcms_phy *);
+ s32 (*rxsigpwr)(struct brcms_phy *, s32);
+ void (*detach)(struct brcms_phy *);
};
struct brcms_phy {
struct brcms_phy_pub pubpi_ro;
struct shared_phy *sh;
struct phy_func_ptr pi_fptr;
- void *pi_ptr;
union {
struct brcms_phy_lcnphy *pi_lcnphy;
} u;
bool user_txpwr_at_rfport;
- d11regs_t *regs;
+ struct d11regs __iomem *regs;
struct brcms_phy *next;
- char *vars;
struct brcms_phy_pub pubpi;
bool do_initcal;
bool phytest_on;
bool ofdm_rateset_war;
bool bf_preempt_4306;
- chanspec_t radio_chanspec;
+ u16 radio_chanspec;
u8 antsel_type;
u16 bw;
u8 txpwr_percent;
@@ -629,7 +583,7 @@ struct brcms_phy {
int phynoise_chan_watchdog;
bool phynoise_polling;
bool disable_percal;
- mbool measure_hold;
+ u32 measure_hold;
s16 txpa_2g[PWRTBL_NUM_COEFF];
s16 txpa_2g_low_temp[PWRTBL_NUM_COEFF];
@@ -723,7 +677,7 @@ struct brcms_phy {
u16 mintxbias;
u16 mintxmag;
struct lo_complex_abgphy_info gphy_locomp_iq
- [STATIC_NUM_RF][STATIC_NUM_BB];
+ [STATIC_NUM_RF][STATIC_NUM_BB];
s8 stats_11b_txpower[STATIC_NUM_RF][STATIC_NUM_BB];
u16 gain_table[TX_GAIN_TABLE_LENGTH];
bool loopback_gain;
@@ -840,11 +794,11 @@ struct brcms_phy {
u8 mphase_txcal_cmdidx;
u8 mphase_txcal_numcmds;
u16 mphase_txcal_bestcoeffs[11];
- chanspec_t nphy_txiqlocal_chanspec;
- chanspec_t nphy_iqcal_chanspec_2G;
- chanspec_t nphy_iqcal_chanspec_5G;
- chanspec_t nphy_rssical_chanspec_2G;
- chanspec_t nphy_rssical_chanspec_5G;
+ u16 nphy_txiqlocal_chanspec;
+ u16 nphy_iqcal_chanspec_2G;
+ u16 nphy_iqcal_chanspec_5G;
+ u16 nphy_rssical_chanspec_2G;
+ u16 nphy_rssical_chanspec_5G;
struct wlapi_timer *phycal_timer;
bool use_int_tx_iqlo_cal_nphy;
bool internal_tx_iqlo_cal_tapoff_intpa_nphy;
@@ -937,9 +891,9 @@ struct brcms_phy {
struct wiphy *wiphy;
};
-struct _cs32 {
- fixed q;
- fixed i;
+struct cs32 {
+ s32 q;
+ s32 i;
};
struct radio_regs {
@@ -964,29 +918,6 @@ struct lcnphy_radio_regs {
u8 do_init_g;
};
-extern struct lcnphy_radio_regs lcnphy_radio_regs_2064[];
-extern struct lcnphy_radio_regs lcnphy_radio_regs_2066[];
-extern struct radio_regs regs_2055[], regs_SYN_2056[], regs_TX_2056[],
- regs_RX_2056[];
-extern struct radio_regs regs_SYN_2056_A1[], regs_TX_2056_A1[],
- regs_RX_2056_A1[];
-extern struct radio_regs regs_SYN_2056_rev5[], regs_TX_2056_rev5[],
- regs_RX_2056_rev5[];
-extern struct radio_regs regs_SYN_2056_rev6[], regs_TX_2056_rev6[],
- regs_RX_2056_rev6[];
-extern struct radio_regs regs_SYN_2056_rev7[], regs_TX_2056_rev7[],
- regs_RX_2056_rev7[];
-extern struct radio_regs regs_SYN_2056_rev8[], regs_TX_2056_rev8[],
- regs_RX_2056_rev8[];
-extern struct radio_20xx_regs regs_2057_rev4[], regs_2057_rev5[],
- regs_2057_rev5v1[];
-extern struct radio_20xx_regs regs_2057_rev7[], regs_2057_rev8[];
-
-extern char *phy_getvar(struct brcms_phy *pi, const char *name);
-extern int phy_getintvar(struct brcms_phy *pi, const char *name);
-#define PHY_GETVAR(pi, name) phy_getvar(pi, name)
-#define PHY_GETINTVAR(pi, name) phy_getintvar(pi, name)
-
extern u16 read_phy_reg(struct brcms_phy *pi, u16 addr);
extern void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val);
extern void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val);
@@ -1022,14 +953,13 @@ extern void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val);
extern void write_phy_channel_reg(struct brcms_phy *pi, uint val);
extern void wlc_phy_txpower_update_shm(struct brcms_phy *pi);
-extern void wlc_phy_cordic(fixed theta, cs32 *val);
extern u8 wlc_phy_nbits(s32 value);
extern void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_dB, u8 core);
extern uint wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi,
struct radio_20xx_regs *radioregs);
extern uint wlc_phy_init_radio_regs(struct brcms_phy *pi,
- struct radio_regs *radioregs,
+ const struct radio_regs *radioregs,
u16 core_offset);
extern void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi);
@@ -1053,14 +983,14 @@ extern void wlc_phy_cal_init_nphy(struct brcms_phy *pi);
extern void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi);
extern void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi,
- chanspec_t chanspec);
+ u16 chanspec);
extern void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi,
- chanspec_t chanspec);
+ u16 chanspec);
extern void wlc_phy_chanspec_set_fixup_lcnphy(struct brcms_phy *pi,
- chanspec_t chanspec);
+ u16 chanspec);
extern int wlc_phy_channel2freq(uint channel);
extern int wlc_phy_chanspec_freq2bandrange_lpssn(uint);
-extern int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, chanspec_t);
+extern int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, u16 chanspec);
extern void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode);
extern s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi);
@@ -1142,13 +1072,17 @@ extern void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi,
bool enable);
extern void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode);
-#define wlc_phy_write_table_nphy(pi, pti) wlc_phy_write_table(pi, pti, 0x72, \
- 0x74, 0x73)
-#define wlc_phy_read_table_nphy(pi, pti) wlc_phy_read_table(pi, pti, 0x72, \
- 0x74, 0x73)
-#define wlc_nphy_table_addr(pi, id, off) wlc_phy_table_addr((pi), (id), (off), \
- 0x72, 0x74, 0x73)
-#define wlc_nphy_table_data_write(pi, w, v) wlc_phy_table_data_write((pi), (w), (v))
+#define wlc_phy_write_table_nphy(pi, pti) \
+ wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73)
+
+#define wlc_phy_read_table_nphy(pi, pti) \
+ wlc_phy_read_table(pi, pti, 0x72, 0x74, 0x73)
+
+#define wlc_nphy_table_addr(pi, id, off) \
+ wlc_phy_table_addr((pi), (id), (off), 0x72, 0x74, 0x73)
+
+#define wlc_nphy_table_data_write(pi, w, v) \
+ wlc_phy_table_data_write((pi), (w), (v))
extern void wlc_phy_table_read_nphy(struct brcms_phy *pi, u32, u32 l, u32 o,
u32 w, void *d);
@@ -1160,7 +1094,7 @@ extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32,
(pi->ipa5g_on && CHSPEC_IS5G(pi->radio_chanspec)))
#define BRCMS_PHY_WAR_PR51571(pi) \
- if (((pi)->sh->bustype == PCI_BUS) && NREV_LT((pi)->pubpi.phy_rev, 3)) \
+ if (NREV_LT((pi)->pubpi.phy_rev, 3)) \
(void)R_REG(&(pi)->regs->maccontrol)
extern void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype);
@@ -1219,7 +1153,7 @@ extern void wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf,
extern void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi);
extern int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi,
- struct brcms_d11rxhdr *wlc_rxh);
+ struct d11rxhdr *rxh);
#define NPHY_TESTPATTERN_BPHY_EVM 0
#define NPHY_TESTPATTERN_BPHY_RFCS 1
@@ -1229,7 +1163,7 @@ extern void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs);
void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset,
s8 *ofdmoffset);
extern s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi,
- chanspec_t chanspec);
+ u16 chanspec);
extern bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih);
#endif /* _BRCM_PHY_INT_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/staging/brcm80211/brcmsmac/phy/phy_lcn.c
index 6a3fbe67302f..a63aa99d9810 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -14,7 +14,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/cordic.h>
#include <pmu.h>
#include <d11.h>
@@ -67,6 +69,14 @@
#define LCN_TEMPSENSE_OFFSET 80812
#define LCN_TEMPSENSE_DEN 2647
+#define LCN_BW_LMT 200
+#define LCN_CUR_LMT 1250
+#define LCN_MULT 1
+#define LCN_VCO_DIV 30
+#define LCN_OFFSET 680
+#define LCN_FACT 490
+#define LCN_CUR_DIV 2640
+
#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \
(0 + 8)
#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \
@@ -79,15 +89,15 @@
#define wlc_lcnphy_enable_tx_gain_override(pi) \
wlc_lcnphy_set_tx_gain_override(pi, true)
-#define wlc_lcnphy_disable_tx_gain_override(pi) \
+#define wlc_lcnphy_disable_tx_gain_override(pi) \
wlc_lcnphy_set_tx_gain_override(pi, false)
#define wlc_lcnphy_iqcal_active(pi) \
(read_phy_reg((pi), 0x451) & \
- ((0x1 << 15) | (0x1 << 14)))
+ ((0x1 << 15) | (0x1 << 14)))
#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13))
-#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
+#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \
(pi->temppwrctrl_capable)
#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \
(pi->hwpwrctrl_capable)
@@ -132,12 +142,12 @@
#define LCNPHY_ACI_DETECT_TIMEOUT 2
#define LCNPHY_ACI_START_DELAY 0
-#define wlc_lcnphy_tx_gain_override_enabled(pi) \
+#define wlc_lcnphy_tx_gain_override_enabled(pi) \
(0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6)))
#define wlc_lcnphy_total_tx_frames(pi) \
- wlapi_bmac_read_shm((pi)->sh->physhim, \
- M_UCODE_MACSTAT + offsetof(struct macstat, txallfrm))
+ wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \
+ offsetof(struct macstat, txallfrm))
struct lcnphy_txgains {
u16 gm_gain;
@@ -198,7 +208,7 @@ static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = {
static const u16 iqcal_gainparams_numgains_lcnphy[1] = {
sizeof(tbl_iqcal_gainparams_lcnphy_2G) /
- sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
+ sizeof(*tbl_iqcal_gainparams_lcnphy_2G),
};
static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = {
@@ -548,7 +558,7 @@ struct chan_info_2064_lcnphy {
u8 rxrf_rxrf_spare1;
};
-static struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
+static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
{1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
{2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
{3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
@@ -565,7 +575,7 @@ static struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = {
{14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80},
};
-struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
+static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
{0x00, 0, 0, 0, 0},
{0x01, 0x64, 0x64, 0, 0},
{0x02, 0x20, 0x20, 0, 0},
@@ -877,7 +887,7 @@ struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = {
#define LCNPHY_NUM_DIG_FILT_COEFFS 16
#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13
-u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
+static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
[LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
{0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64,
128, 64,},
@@ -908,7 +918,7 @@ u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK]
};
#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3
-u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
+static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
[LCNPHY_NUM_DIG_FILT_COEFFS + 1] = {
{0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
0x278, 0xfea0, 0x80, 0x100, 0x80,},
@@ -920,108 +930,50 @@ u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM]
#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \
mod_phy_reg(pi, 0x4a4, \
- (0x1ff << 0), \
- (u16)(idx) << 0)
+ (0x1ff << 0), \
+ (u16)(idx) << 0)
#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \
mod_phy_reg(pi, 0x4a5, \
- (0x7 << 8), \
- (u16)(npt) << 8)
+ (0x7 << 8), \
+ (u16)(npt) << 8)
#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \
(read_phy_reg((pi), 0x4a4) & \
- ((0x1 << 15) | \
- (0x1 << 14) | \
- (0x1 << 13)))
+ ((0x1 << 15) | \
+ (0x1 << 14) | \
+ (0x1 << 13)))
#define wlc_lcnphy_get_tx_pwr_npt(pi) \
((read_phy_reg(pi, 0x4a5) & \
- (0x7 << 8)) >> \
- 8)
+ (0x7 << 8)) >> \
+ 8)
#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \
(read_phy_reg(pi, 0x473) & 0x1ff)
#define wlc_lcnphy_get_target_tx_pwr(pi) \
((read_phy_reg(pi, 0x4a7) & \
- (0xff << 0)) >> \
- 0)
+ (0xff << 0)) >> \
+ 0)
#define wlc_lcnphy_set_target_tx_pwr(pi, target) \
mod_phy_reg(pi, 0x4a7, \
- (0xff << 0), \
- (u16)(target) << 0)
+ (0xff << 0), \
+ (u16)(target) << 0)
+
+#define wlc_radio_2064_rcal_done(pi) \
+ (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
+
+#define tempsense_done(pi) \
+ (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
-#define wlc_radio_2064_rcal_done(pi) (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20))
-#define tempsense_done(pi) (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000))
+#define LCNPHY_IQLOCC_READ(val) \
+ ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
-#define LCNPHY_IQLOCC_READ(val) ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f)))
#define FIXED_TXPWR 78
#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val))
-static u32 wlc_lcnphy_qdiv_roundup(u32 divident, u32 divisor,
- u8 precision);
-static void wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
- u16 ext_lna, u16 trsw,
- u16 biq2, u16 biq1,
- u16 tia, u16 lna2,
- u16 lna1);
-static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi);
-static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain);
-static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx,
- bool rx);
-static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0);
-static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi);
-static void wlc_lcnphy_get_tx_gain(struct brcms_phy *pi,
- struct lcnphy_txgains *gains);
-static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable);
-static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi);
-static void wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi,
- bool enable);
-static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
- struct lcnphy_txgains *target_gains);
-static bool wlc_lcnphy_rx_iq_est(struct brcms_phy *pi, u16 num_samps,
- u8 wait_time, struct lcnphy_iq_est *iq_est);
-static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps);
-static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi);
-static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode);
-static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi);
-static void wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi,
- u8 channel);
-
-static void wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
- const struct lcnphy_tx_gain_tbl_entry *g);
-
-static void wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo,
- u16 thresh, s16 *ptr, int mode);
-static int wlc_lcnphy_calc_floor(s16 coeff, int type);
-static void wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi,
- u16 *values_to_save);
-static void wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi,
- u16 *values_to_save);
-static void wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x,
- s16 coeff_y);
-static struct lcnphy_unsign16_struct wlc_lcnphy_get_cc(struct brcms_phy *pi,
- int cal_type);
-static void wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type,
- int num_levels, int step_size_lg2);
-static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi);
-
-static void wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi,
- chanspec_t chanspec);
-static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi);
-static void wlc_lcnphy_temp_adj(struct brcms_phy *pi);
-static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi);
-static void wlc_lcnphy_baseband_init(struct brcms_phy *pi);
-static void wlc_lcnphy_radio_init(struct brcms_phy *pi);
-static void wlc_lcnphy_rc_cal(struct brcms_phy *pi);
-static void wlc_lcnphy_rcal(struct brcms_phy *pi);
-static void wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi,
- bool enable);
-static int wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm,
- s16 filt_type);
-static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b);
-
void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti)
{
wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456);
@@ -1034,7 +986,7 @@ void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti)
static void
wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
- const void *tbl_ptr, u32 tbl_len,
+ const u16 *tbl_ptr, u32 tbl_len,
u32 tbl_width, u32 tbl_offset)
{
struct phytbl_info tab;
@@ -1048,7 +1000,7 @@ wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id,
static void
wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id,
- const void *tbl_ptr, u32 tbl_len,
+ const u16 *tbl_ptr, u32 tbl_len,
u32 tbl_width, u32 tbl_offset)
{
@@ -1092,12 +1044,12 @@ static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
int k;
k = 0;
if (type == 0) {
- if (coeff_x < 0) {
+ if (coeff_x < 0)
k = (coeff_x - 1) / 2;
- } else {
+ else
k = coeff_x / 2;
- }
}
+
if (type == 1) {
if ((coeff_x + 1) < 0)
k = (coeff_x) / 2;
@@ -1107,20 +1059,265 @@ static int wlc_lcnphy_calc_floor(s16 coeff_x, int type)
return k;
}
-s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
+static void
+wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
{
- s8 index;
+ u16 dac_gain, rfgain0, rfgain1;
+
+ dac_gain = read_phy_reg(pi, 0x439) >> 0;
+ gains->dac_gain = (dac_gain & 0x380) >> 7;
+
+ rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
+ rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
+
+ gains->gm_gain = rfgain0 & 0xff;
+ gains->pga_gain = (rfgain0 >> 8) & 0xff;
+ gains->pad_gain = rfgain1 & 0xff;
+}
+
+
+static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
+{
+ u16 dac_ctrl;
+
+ dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
+ dac_ctrl = dac_ctrl & 0xc7f;
+ dac_ctrl = dac_ctrl | (dac_gain << 7);
+ mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
+
+}
+
+static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
+{
+ u16 bit = bEnable ? 1 : 0;
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
+}
+
+static void
+wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
+{
+ u16 ebit = enable ? 1 : 0;
+
+ mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
+
+ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
+ mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
+ mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
+ } else {
+ mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
+ mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
+ mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
+ }
+}
+
+static void
+wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
+ u16 trsw,
+ u16 ext_lna,
+ u16 biq2,
+ u16 biq1,
+ u16 tia, u16 lna2, u16 lna1)
+{
+ u16 gain0_15, gain16_19;
+
+ gain16_19 = biq2 & 0xf;
+ gain0_15 = ((biq1 & 0xf) << 12) |
+ ((tia & 0xf) << 8) |
+ ((lna2 & 0x3) << 6) |
+ ((lna2 &
+ 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
+
+ mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
+ mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
+ mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
+
+ if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
+ mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
+ } else {
+ mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
+
+ mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
+
+ mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
+ }
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
+
+}
+
+static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
+{
+
+ mod_phy_reg(pi, 0x44d,
+ (0x1 << 1) |
+ (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
+
+ or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
+}
+
+static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
+{
+
+ and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
+}
+
+static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
+{
+ mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
+
+ mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
+
+ mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
+
+ mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
+
+ mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
+
+ mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
+
+}
+
+static bool
+wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
+ u16 num_samps,
+ u8 wait_time, struct lcnphy_iq_est *iq_est)
+{
+ int wait_count = 0;
+ bool result = true;
+ u8 phybw40;
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
+
+ mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
+
+ mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
+
+ mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
+
+ mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
+
+ mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
+
+ while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
+
+ if (wait_count > (10 * 500)) {
+ result = false;
+ goto cleanup;
+ }
+ udelay(100);
+ wait_count++;
+ }
+
+ iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
+ (u32) read_phy_reg(pi, 0x484);
+ iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
+ (u32) read_phy_reg(pi, 0x486);
+ iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
+ (u32) read_phy_reg(pi, 0x488);
+
+cleanup:
+ mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
+
+ mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
+
+ return result;
+}
+
+static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
+{
+#define LCNPHY_MIN_RXIQ_PWR 2
+ bool result;
+ u16 a0_new, b0_new;
+ struct lcnphy_iq_est iq_est = { 0, 0, 0 };
+ s32 a, b, temp;
+ s16 iq_nbits, qq_nbits, arsh, brsh;
+ s32 iq;
+ u32 ii, qq;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- if (txpwrctrl_off(pi))
- index = pi_lcn->lcnphy_current_index;
- else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
- index =
- (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi)
- / 2);
- else
- index = pi_lcn->lcnphy_current_index;
- return index;
+ a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
+ b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
+ mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
+
+ mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
+
+ wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
+
+ result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
+ if (!result)
+ goto cleanup;
+
+ iq = (s32) iq_est.iq_prod;
+ ii = iq_est.i_pwr;
+ qq = iq_est.q_pwr;
+
+ if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
+ result = false;
+ goto cleanup;
+ }
+
+ iq_nbits = wlc_phy_nbits(iq);
+ qq_nbits = wlc_phy_nbits(qq);
+
+ arsh = 10 - (30 - iq_nbits);
+ if (arsh >= 0) {
+ a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
+ temp = (s32) (ii >> arsh);
+ if (temp == 0)
+ return false;
+ } else {
+ a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
+ temp = (s32) (ii << -arsh);
+ if (temp == 0)
+ return false;
+ }
+ a /= temp;
+ brsh = qq_nbits - 31 + 20;
+ if (brsh >= 0) {
+ b = (qq << (31 - qq_nbits));
+ temp = (s32) (ii >> brsh);
+ if (temp == 0)
+ return false;
+ } else {
+ b = (qq << (31 - qq_nbits));
+ temp = (s32) (ii << -brsh);
+ if (temp == 0)
+ return false;
+ }
+ b /= temp;
+ b -= a * a;
+ b = (s32) int_sqrt((unsigned long) b);
+ b -= (1 << 10);
+ a0_new = (u16) (a & 0x3ff);
+ b0_new = (u16) (b & 0x3ff);
+cleanup:
+
+ wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
+
+ mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
+
+ pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
+ pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
+
+ return result;
}
static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
@@ -1132,6 +1329,187 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
}
+static bool
+wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
+ const struct lcnphy_rx_iqcomp *iqcomp,
+ int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
+ int tx_gain_idx)
+{
+ struct lcnphy_txgains old_gains;
+ u16 tx_pwr_ctrl;
+ u8 tx_gain_index_old = 0;
+ bool result = false, tx_gain_override_old = false;
+ u16 i, Core1TxControl_old, RFOverride0_old,
+ RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
+ rfoverride3_old, rfoverride3val_old, rfoverride4_old,
+ rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
+ int tia_gain;
+ u32 received_power, rx_pwr_threshold;
+ u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
+ u16 values_to_save[11];
+ s16 *ptr;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
+ if (NULL == ptr)
+ return false;
+ if (module == 2) {
+ while (iqcomp_sz--) {
+ if (iqcomp[iqcomp_sz].chan ==
+ CHSPEC_CHANNEL(pi->radio_chanspec)) {
+ wlc_lcnphy_set_rx_iq_comp(pi,
+ (u16)
+ iqcomp[iqcomp_sz].a,
+ (u16)
+ iqcomp[iqcomp_sz].b);
+ result = true;
+ break;
+ }
+ }
+ goto cal_done;
+ }
+
+ if (module == 1) {
+
+ tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
+
+ for (i = 0; i < 11; i++)
+ values_to_save[i] =
+ read_radio_reg(pi, rxiq_cal_rf_reg[i]);
+ Core1TxControl_old = read_phy_reg(pi, 0x631);
+
+ or_phy_reg(pi, 0x631, 0x0015);
+
+ RFOverride0_old = read_phy_reg(pi, 0x44c);
+ RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
+ rfoverride2_old = read_phy_reg(pi, 0x4b0);
+ rfoverride2val_old = read_phy_reg(pi, 0x4b1);
+ rfoverride3_old = read_phy_reg(pi, 0x4f9);
+ rfoverride3val_old = read_phy_reg(pi, 0x4fa);
+ rfoverride4_old = read_phy_reg(pi, 0x938);
+ rfoverride4val_old = read_phy_reg(pi, 0x939);
+ afectrlovr_old = read_phy_reg(pi, 0x43b);
+ afectrlovrval_old = read_phy_reg(pi, 0x43c);
+ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+ old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
+
+ tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
+ if (tx_gain_override_old) {
+ wlc_lcnphy_get_tx_gain(pi, &old_gains);
+ tx_gain_index_old = pi_lcn->lcnphy_current_index;
+ }
+
+ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
+
+ mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+
+ write_radio_reg(pi, RADIO_2064_REG116, 0x06);
+ write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
+ write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
+ write_radio_reg(pi, RADIO_2064_REG098, 0x03);
+ write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
+ mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
+ write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
+ write_radio_reg(pi, RADIO_2064_REG114, 0x01);
+ write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
+ write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
+
+ mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
+ mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
+ mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
+ mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
+ mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+
+ wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
+ write_phy_reg(pi, 0x6da, 0xffff);
+ or_phy_reg(pi, 0x6db, 0x3);
+ wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
+ wlc_lcnphy_rx_gain_override_enable(pi, true);
+
+ tia_gain = 8;
+ rx_pwr_threshold = 950;
+ while (tia_gain > 0) {
+ tia_gain -= 1;
+ wlc_lcnphy_set_rx_gain_by_distribution(pi,
+ 0, 0, 2, 2,
+ (u16)
+ tia_gain, 1, 0);
+ udelay(500);
+
+ received_power =
+ wlc_lcnphy_measure_digital_power(pi, 2000);
+ if (received_power < rx_pwr_threshold)
+ break;
+ }
+ result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
+
+ wlc_lcnphy_stop_tx_tone(pi);
+
+ write_phy_reg(pi, 0x631, Core1TxControl_old);
+
+ write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
+ write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
+ write_phy_reg(pi, 0x4b0, rfoverride2_old);
+ write_phy_reg(pi, 0x4b1, rfoverride2val_old);
+ write_phy_reg(pi, 0x4f9, rfoverride3_old);
+ write_phy_reg(pi, 0x4fa, rfoverride3val_old);
+ write_phy_reg(pi, 0x938, rfoverride4_old);
+ write_phy_reg(pi, 0x939, rfoverride4val_old);
+ write_phy_reg(pi, 0x43b, afectrlovr_old);
+ write_phy_reg(pi, 0x43c, afectrlovrval_old);
+ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
+ write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
+
+ wlc_lcnphy_clear_trsw_override(pi);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
+
+ for (i = 0; i < 11; i++)
+ write_radio_reg(pi, rxiq_cal_rf_reg[i],
+ values_to_save[i]);
+
+ if (tx_gain_override_old)
+ wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
+ else
+ wlc_lcnphy_disable_tx_gain_override(pi);
+
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
+ wlc_lcnphy_rx_gain_override_enable(pi, false);
+ }
+
+cal_done:
+ kfree(ptr);
+ return result;
+}
+
+s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi)
+{
+ s8 index;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (txpwrctrl_off(pi))
+ index = pi_lcn->lcnphy_current_index;
+ else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi))
+ index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(
+ pi) / 2);
+ else
+ index = pi_lcn->lcnphy_current_index;
+ return index;
+}
+
void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel)
{
u16 afectrlovr, afectrlovrval;
@@ -1200,7 +1578,290 @@ wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable)
wlapi_switch_macfreq(pi->sh->physhim, enable);
}
-void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, chanspec_t chanspec)
+static void
+wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec)
+{
+ u8 channel = CHSPEC_CHANNEL(chanspec);
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ if (channel == 14)
+ mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
+ else
+ mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
+
+ pi_lcn->lcnphy_bandedge_corr = 2;
+ if (channel == 1)
+ pi_lcn->lcnphy_bandedge_corr = 4;
+
+ if (channel == 1 || channel == 2 || channel == 3 ||
+ channel == 4 || channel == 9 ||
+ channel == 10 || channel == 11 || channel == 12) {
+ si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
+ si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
+ si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
+
+ si_pmu_pllupd(pi->sh->sih);
+ write_phy_reg(pi, 0x942, 0);
+ wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
+ pi_lcn->lcnphy_spurmod = 0;
+ mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
+
+ write_phy_reg(pi, 0x425, 0x5907);
+ } else {
+ si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
+ si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
+ si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
+
+ si_pmu_pllupd(pi->sh->sih);
+ write_phy_reg(pi, 0x942, 0);
+ wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
+
+ pi_lcn->lcnphy_spurmod = 0;
+ mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
+
+ write_phy_reg(pi, 0x425, 0x590a);
+ }
+
+ or_phy_reg(pi, 0x44a, 0x44);
+ write_phy_reg(pi, 0x44a, 0x80);
+}
+
+static void
+wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
+{
+ uint i;
+ const struct chan_info_2064_lcnphy *ci;
+ u8 rfpll_doubler = 0;
+ u8 pll_pwrup, pll_pwrup_ovr;
+ s32 qFxtal, qFref, qFvco, qFcal;
+ u8 d15, d16, f16, e44, e45;
+ u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
+ u16 loop_bw, d30, setCount;
+
+ u8 h29, h28_ten, e30, h30_ten, cp_current;
+ u16 g30, d28;
+
+ ci = &chan_info_2064_lcnphy[0];
+ rfpll_doubler = 1;
+
+ mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
+
+ write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
+ if (!rfpll_doubler) {
+ loop_bw = PLL_2064_LOOP_BW;
+ d30 = PLL_2064_D30;
+ } else {
+ loop_bw = PLL_2064_LOOP_BW_DOUBLER;
+ d30 = PLL_2064_D30_DOUBLER;
+ }
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
+ if (chan_info_2064_lcnphy[i].chan == channel)
+ break;
+
+ if (i >= ARRAY_SIZE(chan_info_2064_lcnphy))
+ return;
+
+ ci = &chan_info_2064_lcnphy[i];
+ }
+
+ write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
+
+ mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
+
+ mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
+
+ mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
+
+ mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
+ (ci->logen_rccr_rx) << 2);
+
+ mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
+
+ mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
+ (ci->pa_rxrf_lna2_freq_tune) << 4);
+
+ write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
+
+ pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
+ pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
+
+ or_radio_reg(pi, RADIO_2064_REG044, 0x07);
+
+ or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
+ e44 = 0;
+ e45 = 0;
+
+ fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
+ if (pi->xtalfreq > 26000000)
+ e44 = 1;
+ if (pi->xtalfreq > 52000000)
+ e45 = 1;
+ if (e44 == 0)
+ fcal_div = 1;
+ else if (e45 == 0)
+ fcal_div = 2;
+ else
+ fcal_div = 4;
+ fvco3 = (ci->freq * 3);
+ fref3 = 2 * fpfd;
+
+ qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
+ qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
+ qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
+ qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
+
+ write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
+
+ d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
+ write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
+ write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
+
+ d16 = (qFcal * 8 / (d15 + 1)) - 1;
+ write_radio_reg(pi, RADIO_2064_REG051, d16);
+
+ f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
+ setCount = f16 * 3 * (ci->freq) / 32 - 1;
+ mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
+ (u8) (setCount >> 8));
+
+ or_radio_reg(pi, RADIO_2064_REG053, 0x10);
+ write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
+
+ div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
+
+ div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
+ while (div_frac >= fref3) {
+ div_int++;
+ div_frac -= fref3;
+ }
+ div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
+
+ mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
+ (u8) (div_int >> 4));
+ mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
+ (u8) (div_int << 4));
+ mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
+ (u8) (div_frac >> 16));
+ write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
+ write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
+
+ write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
+
+ write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
+ write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
+ write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
+
+ h29 = LCN_BW_LMT / loop_bw;
+ d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
+ (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
+ (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
+ + PLL_2064_LOW_END_KVCO;
+ h28_ten = (d28 * 10) / LCN_VCO_DIV;
+ e30 = (d30 - LCN_OFFSET) / LCN_FACT;
+ g30 = LCN_OFFSET + (e30 * LCN_FACT);
+ h30_ten = (g30 * 10) / LCN_CUR_DIV;
+ cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten;
+ mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
+
+ if (channel >= 1 && channel <= 5)
+ write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
+ else
+ write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
+ write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
+
+ mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
+ udelay(1);
+
+ wlc_2064_vco_cal(pi);
+
+ write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
+ write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+ write_radio_reg(pi, RADIO_2064_REG038, 3);
+ write_radio_reg(pi, RADIO_2064_REG091, 7);
+ }
+}
+
+static int
+wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
+{
+ s16 filt_index = -1;
+ int j;
+
+ u16 addr[] = {
+ 0x910,
+ 0x91e,
+ 0x91f,
+ 0x924,
+ 0x925,
+ 0x926,
+ 0x920,
+ 0x921,
+ 0x927,
+ 0x928,
+ 0x929,
+ 0x922,
+ 0x923,
+ 0x930,
+ 0x931,
+ 0x932
+ };
+
+ u16 addr_ofdm[] = {
+ 0x90f,
+ 0x900,
+ 0x901,
+ 0x906,
+ 0x907,
+ 0x908,
+ 0x902,
+ 0x903,
+ 0x909,
+ 0x90a,
+ 0x90b,
+ 0x904,
+ 0x905,
+ 0x90c,
+ 0x90d,
+ 0x90e
+ };
+
+ if (!is_ofdm) {
+ for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
+ if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
+ filt_index = (s16) j;
+ break;
+ }
+ }
+
+ if (filt_index != -1) {
+ for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr[j],
+ LCNPHY_txdigfiltcoeffs_cck
+ [filt_index][j + 1]);
+ }
+ } else {
+ for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
+ if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
+ filt_index = (s16) j;
+ break;
+ }
+ }
+
+ if (filt_index != -1) {
+ for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr_ofdm[j],
+ LCNPHY_txdigfiltcoeffs_ofdm
+ [filt_index][j + 1]);
+ }
+ }
+
+ return (filt_index != -1) ? 0 : -1;
+}
+
+void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
{
u8 channel = CHSPEC_CHANNEL(chanspec);
@@ -1211,10 +1872,8 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, chanspec_t chanspec)
or_phy_reg(pi, 0x44a, 0x44);
write_phy_reg(pi, 0x44a, 0x80);
- if (!NORADIO_ENAB(pi->pubpi)) {
- wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
- udelay(1000);
- }
+ wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel);
+ udelay(1000);
wlc_lcnphy_toggle_afe_pwdn(pi);
@@ -1237,35 +1896,13 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, chanspec_t chanspec)
}
-static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain)
-{
- u16 dac_ctrl;
-
- dac_ctrl = (read_phy_reg(pi, 0x439) >> 0);
- dac_ctrl = dac_ctrl & 0xc7f;
- dac_ctrl = dac_ctrl | (dac_gain << 7);
- mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0);
-
-}
-
-static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable)
-{
- u16 bit = bEnable ? 1 : 0;
-
- mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7);
-
- mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14);
-
- mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6);
-}
-
static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi)
{
u16 pa_gain;
pa_gain = (read_phy_reg(pi, 0x4fb) &
LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >>
- LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
+ LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT;
return pa_gain;
}
@@ -1275,18 +1912,22 @@ static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi,
{
u16 pa_gain = wlc_lcnphy_get_pa_gain(pi);
- mod_phy_reg(pi, 0x4b5,
- (0xffff << 0),
- ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
- 0);
+ mod_phy_reg(
+ pi, 0x4b5,
+ (0xffff << 0),
+ ((target_gains->gm_gain) |
+ (target_gains->pga_gain << 8)) <<
+ 0);
mod_phy_reg(pi, 0x4fb,
(0x7fff << 0),
((target_gains->pad_gain) | (pa_gain << 8)) << 0);
- mod_phy_reg(pi, 0x4fc,
- (0xffff << 0),
- ((target_gains->gm_gain) | (target_gains->pga_gain << 8)) <<
- 0);
+ mod_phy_reg(
+ pi, 0x4fc,
+ (0xffff << 0),
+ ((target_gains->gm_gain) |
+ (target_gains->pga_gain << 8)) <<
+ 0);
mod_phy_reg(pi, 0x4fd,
(0x7fff << 0),
((target_gains->pad_gain) | (pa_gain << 8)) << 0);
@@ -1404,8 +2045,8 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- auxpga_vmid =
- (2 << 8) | (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
+ auxpga_vmid = (2 << 8) |
+ (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf;
auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4;
auxpga_gain_temp = 2;
@@ -1531,10 +2172,9 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3);
- if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
+ if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
mod_phy_reg(pi, 0x4d7,
(0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12);
- }
rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi);
tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
@@ -1601,7 +2241,7 @@ void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi)
{
struct phytbl_info tab;
u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM +
- BRCMS_NUM_RATES_MCS_1_STREAM];
+ BRCMS_NUM_RATES_MCS_1_STREAM];
uint i, j;
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
return;
@@ -1694,34 +2334,28 @@ static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
index = FIXED_TXPWR;
- if (NORADIO_ENAB(pi->pubpi))
+ if (pi_lcn->lcnphy_tempsense_slope == 0)
return index;
- if (pi_lcn->lcnphy_tempsense_slope == 0) {
- return index;
- }
temp = (u16) wlc_lcnphy_tempsense(pi, 0);
meas_temp = LCNPHY_TEMPSENSE(temp);
- if (pi->tx_power_min != 0) {
+ if (pi->tx_power_min != 0)
delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min);
- } else {
+ else
delta_brd = 0;
- }
manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense);
temp_diff = manp - meas_temp;
if (temp_diff < 0) {
-
neg = 1;
-
temp_diff = -temp_diff;
}
delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192),
- (u32) (pi_lcn->
- lcnphy_tempsense_slope
- * 10), 0);
+ (u32) (pi_lcn->
+ lcnphy_tempsense_slope
+ * 10), 0);
if (neg)
delta_temp = -delta_temp;
@@ -1735,14 +2369,15 @@ static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi)
if (LCNREV_IS(pi->pubpi.phy_rev, 1))
tempcorrx = 4;
new_index =
- index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
+ index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr;
new_index += tempcorrx;
if (LCNREV_IS(pi->pubpi.phy_rev, 1))
index = 127;
- if (new_index < 0 || new_index > 126) {
+
+ if (new_index < 0 || new_index > 126)
return index;
- }
+
return new_index;
}
@@ -1792,7 +2427,7 @@ void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0);
pi_lcn->lcnphy_tssi_tx_cnt =
- wlc_lcnphy_total_tx_frames(pi);
+ wlc_lcnphy_total_tx_frames(pi);
wlc_lcnphy_disable_tx_gain_override(pi);
pi_lcn->lcnphy_tx_power_idx_override = -1;
@@ -1805,11 +2440,105 @@ void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode)
index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index);
pi_lcn->lcnphy_current_index = (s8)
- ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
+ ((read_phy_reg(pi,
+ 0x4a9) &
+ 0xFF) / 2);
}
}
}
+static void
+wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
+{
+ u16 vmid;
+ int i;
+ for (i = 0; i < 20; i++)
+ values_to_save[i] =
+ read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
+ mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
+
+ mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
+ mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+ mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+
+ mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
+ mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2))
+ and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
+ else
+ and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
+ or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
+
+ or_radio_reg(pi, RADIO_2064_REG036, 0x01);
+ or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
+ udelay(20);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
+ else
+ or_radio_reg(pi, RADIO_2064_REG03A, 1);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
+ else
+ or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
+ }
+
+ udelay(20);
+
+ write_radio_reg(pi, RADIO_2064_REG025, 0xF);
+ if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
+ else
+ mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
+ else
+ mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
+ }
+
+ udelay(20);
+
+ write_radio_reg(pi, RADIO_2064_REG005, 0x8);
+ or_radio_reg(pi, RADIO_2064_REG112, 0x80);
+ udelay(20);
+
+ or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
+ or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
+ udelay(20);
+
+ or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
+ or_radio_reg(pi, RADIO_2064_REG113, 0x10);
+ udelay(20);
+
+ write_radio_reg(pi, RADIO_2064_REG007, 0x1);
+ udelay(20);
+
+ vmid = 0x2A6;
+ mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
+ write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
+ or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
+ udelay(20);
+
+ or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
+ udelay(20);
+ write_radio_reg(pi, RADIO_2064_REG012, 0x02);
+ or_radio_reg(pi, RADIO_2064_REG112, 0x06);
+ write_radio_reg(pi, RADIO_2064_REG036, 0x11);
+ write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
+ write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
+ write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
+ write_radio_reg(pi, RADIO_2064_REG092, 0x15);
+}
+
static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
{
uint delay_count = 0;
@@ -1826,6 +2555,20 @@ static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi)
}
static void
+wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
+{
+ int i;
+
+ and_phy_reg(pi, 0x44c, 0x0 >> 11);
+
+ and_phy_reg(pi, 0x43b, 0xC);
+
+ for (i = 0; i < 20; i++)
+ write_radio_reg(pi, iqlo_loopback_rf_regs[i],
+ values_to_save[i]);
+}
+
+static void
wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
struct lcnphy_txgains *target_gains,
enum lcnphy_cal_mode cal_mode, bool keep_tone)
@@ -1837,20 +2580,23 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
int j;
u16 ncorr_override[5];
u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
- };
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000};
u16 commands_fullcal[] = {
- 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
+ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
+ };
u16 commands_recal[] = {
- 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 };
+ 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234
+ };
u16 command_nums_fullcal[] = {
- 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
+ 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
+ };
u16 command_nums_recal[] = {
- 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 };
+ 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97
+ };
u16 *command_nums = command_nums_fullcal;
u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start;
@@ -1862,13 +2608,9 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
u16 *values_to_save;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
- if (NULL == values_to_save) {
+ if (NULL == values_to_save)
return;
- }
save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
@@ -1927,7 +2669,7 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
}
hash = (target_gains->gm_gain << 8) |
- (target_gains->pga_gain << 4) | (target_gains->pad_gain);
+ (target_gains->pga_gain << 4) | (target_gains->pad_gain);
band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
@@ -1936,11 +2678,11 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) {
if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) {
cal_gains.gm_gain =
- tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
+ tbl_iqcal_gainparams_lcnphy[band_idx][j][1];
cal_gains.pga_gain =
- tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
+ tbl_iqcal_gainparams_lcnphy[band_idx][j][2];
cal_gains.pad_gain =
- tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
+ tbl_iqcal_gainparams_lcnphy[band_idx][j][3];
memcpy(ncorr_override,
&tbl_iqcal_gainparams_lcnphy[band_idx][j][3],
sizeof(ncorr_override));
@@ -1954,14 +2696,14 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
write_phy_reg(pi, 0x93d, 0xc0);
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
- (const void *)
lcnphy_iqcal_loft_gainladder,
ARRAY_SIZE(lcnphy_iqcal_loft_gainladder),
16, 0);
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
- (const void *)lcnphy_iqcal_ir_gainladder,
- ARRAY_SIZE(lcnphy_iqcal_ir_gainladder), 16,
+ lcnphy_iqcal_ir_gainladder,
+ ARRAY_SIZE(
+ lcnphy_iqcal_ir_gainladder), 16,
32);
if (pi->phy_tx_tone_freq) {
@@ -1985,13 +2727,12 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
command_num = command_nums[i];
if (ncorr_override[cal_type])
command_num =
- ncorr_override[cal_type] << 8 | (command_num &
- 0xff);
+ ncorr_override[cal_type] << 8 | (command_num &
+ 0xff);
write_phy_reg(pi, 0x452, command_num);
if ((cal_type == 3) || (cal_type == 4)) {
-
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
&diq_start, 1, 16, 69);
@@ -2001,10 +2742,8 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
write_phy_reg(pi, 0x451, cal_cmds[i]);
- if (!wlc_lcnphy_iqcal_wait(pi)) {
-
+ if (!wlc_lcnphy_iqcal_wait(pi))
goto cleanup;
- }
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
best_coeffs,
@@ -2013,16 +2752,15 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
best_coeffs,
ARRAY_SIZE(best_coeffs), 16, 64);
- if ((cal_type == 3) || (cal_type == 4)) {
+ if ((cal_type == 3) || (cal_type == 4))
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
&diq_start, 1, 16, 69);
- }
wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL,
pi_lcn->lcnphy_cal_results.
txiqlocal_bestcoeffs,
ARRAY_SIZE(pi_lcn->
- lcnphy_cal_results.
- txiqlocal_bestcoeffs),
+ lcnphy_cal_results.
+ txiqlocal_bestcoeffs),
16, 96);
}
@@ -2030,7 +2768,7 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
pi_lcn->lcnphy_cal_results.
txiqlocal_bestcoeffs,
ARRAY_SIZE(pi_lcn->lcnphy_cal_results.
- txiqlocal_bestcoeffs), 16, 96);
+ txiqlocal_bestcoeffs), 16, 96);
pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true;
wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL,
@@ -2041,7 +2779,7 @@ wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi,
&pi_lcn->lcnphy_cal_results.
txiqlocal_bestcoeffs[5], 2, 16, 85);
- cleanup:
+cleanup:
wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save);
kfree(values_to_save);
@@ -2071,14 +2809,14 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112);
u16 SAVE_jtag_bb_afe_switch =
- read_radio_reg(pi, RADIO_2064_REG007) & 1;
+ read_radio_reg(pi, RADIO_2064_REG007) & 1;
u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
idleTssi = read_phy_reg(pi, 0x4ab);
suspend =
- (0 ==
- (R_REG(&((struct brcms_phy *) pi)->regs->maccontrol) &
- MCTL_EN_MAC));
+ (0 ==
+ (R_REG(&((struct brcms_phy *) pi)->regs->maccontrol) &
+ MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
@@ -2136,7 +2874,7 @@ static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
struct phytbl_info tab;
u32 val;
u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025,
- save_reg112;
+ save_reg112;
u16 values_to_save[14];
s8 index;
int i;
@@ -2152,8 +2890,7 @@ static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
for (i = 0; i < 14; i++)
values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]);
- suspend =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4);
@@ -2236,7 +2973,7 @@ static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode)
auxpga_gain = 2;
}
auxpga_vmid =
- (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
+ (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0);
mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2);
@@ -2280,17 +3017,10 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
struct brcms_phy *pi = (struct brcms_phy *) ppi;
suspend =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
- if (NORADIO_ENAB(pi->pubpi)) {
- wlc_lcnphy_set_bbmult(pi, 0x30);
- if (!suspend)
- wlapi_enable_mac(pi->sh->physhim);
- return;
- }
-
if (!pi->hwpwrctrl_capable) {
if (CHSPEC_IS2G(pi->radio_chanspec)) {
tx_gains.gm_gain = 4;
@@ -2382,26 +3112,6 @@ wlc_lcnphy_get_radio_loft(struct brcms_phy *pi,
*fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C));
}
-static void
-wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains)
-{
- u16 dac_gain;
-
- dac_gain = read_phy_reg(pi, 0x439) >> 0;
- gains->dac_gain = (dac_gain & 0x380) >> 7;
-
- {
- u16 rfgain0, rfgain1;
-
- rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0;
- rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0;
-
- gains->gm_gain = rfgain0 & 0xff;
- gains->pga_gain = (rfgain0 >> 8) & 0xff;
- gains->pad_gain = rfgain1 & 0xff;
- }
-}
-
void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b)
{
struct phytbl_info tab;
@@ -2489,16 +3199,6 @@ void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index)
}
}
-static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx)
-{
-
- mod_phy_reg(pi, 0x44d,
- (0x1 << 1) |
- (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0));
-
- or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0));
-}
-
static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
{
u32 j;
@@ -2518,67 +3218,6 @@ static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi)
return;
}
-static void
-wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
- u16 trsw,
- u16 ext_lna,
- u16 biq2,
- u16 biq1,
- u16 tia, u16 lna2, u16 lna1)
-{
- u16 gain0_15, gain16_19;
-
- gain16_19 = biq2 & 0xf;
- gain0_15 = ((biq1 & 0xf) << 12) |
- ((tia & 0xf) << 8) |
- ((lna2 & 0x3) << 6) |
- ((lna2 & 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
-
- mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
- mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
- mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
-
- if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
- mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
- mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10);
- } else {
- mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10);
-
- mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15);
-
- mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9);
- }
-
- mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
-
-}
-
-static void
-wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable)
-{
- u16 ebit = enable ? 1 : 0;
-
- mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8);
-
- mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0);
-
- if (LCNREV_LT(pi->pubpi.phy_rev, 2)) {
- mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4);
- mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6);
- mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
- mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6);
- } else {
- mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12);
- mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13);
- mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5);
- }
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10);
- mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3);
- }
-}
-
void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
{
if (!bEnable) {
@@ -2589,9 +3228,9 @@ void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable)
and_phy_reg(pi, 0x44c,
~(u16) ((0x1 << 3) |
- (0x1 << 5) |
- (0x1 << 12) |
- (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
+ (0x1 << 5) |
+ (0x1 << 12) |
+ (0x1 << 0) | (0x1 << 1) | (0x1 << 2)));
and_phy_reg(pi, 0x44d,
~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14)));
@@ -2701,7 +3340,8 @@ void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode)
mod_phy_reg((pi), 0x410,
(0x1 << 6) |
(0x1 << 5),
- ((CHSPEC_IS2G(pi->radio_chanspec)) ? (!mode) : 0) <<
+ ((CHSPEC_IS2G(
+ pi->radio_chanspec)) ? (!mode) : 0) <<
6 | (!mode) << 5);
mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7);
}
@@ -2714,8 +3354,8 @@ wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
u8 phy_bw;
u16 num_samps, t, k;
u32 bw;
- fixed theta = 0, rot = 0;
- cs32 tone_samp;
+ s32 theta = 0, rot = 0;
+ struct cordic_iq tone_samp;
u32 data_buf[64];
u16 i_samp, q_samp;
struct phytbl_info tab;
@@ -2737,18 +3377,18 @@ wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val,
k = 1;
do {
bw = phy_bw * 1000 * k;
- num_samps = bw / ABS(f_kHz);
+ num_samps = bw / abs(f_kHz);
k++;
- } while ((num_samps * (u32) (ABS(f_kHz))) != bw);
+ } while ((num_samps * (u32) (abs(f_kHz))) != bw);
} else
num_samps = 2;
- rot = FIXED((f_kHz * 36) / phy_bw) / 100;
+ rot = ((f_kHz * 36) / phy_bw) / 100;
theta = 0;
for (t = 0; t < num_samps; t++) {
- wlc_phy_cordic(theta, &tone_samp);
+ tone_samp = cordic_calc_iq(theta);
theta += rot;
@@ -2802,10 +3442,359 @@ void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi)
wlc_lcnphy_deaf_mode(pi, false);
}
-static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi)
+static void
+wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
{
+ u16 di0dq0;
+ u16 x, y, data_rf;
+ int k;
+ switch (cal_type) {
+ case 0:
+ wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
+ break;
+ case 2:
+ di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
+ wlc_lcnphy_set_tx_locc(pi, di0dq0);
+ break;
+ case 3:
+ k = wlc_lcnphy_calc_floor(coeff_x, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_x, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG089, data_rf);
+ k = wlc_lcnphy_calc_floor(coeff_y, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_y, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
+ break;
+ case 4:
+ k = wlc_lcnphy_calc_floor(coeff_x, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_x, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
+ k = wlc_lcnphy_calc_floor(coeff_y, 0);
+ y = 8 + k;
+ k = wlc_lcnphy_calc_floor(coeff_y, 1);
+ x = 8 - k;
+ data_rf = (x * 16 + y);
+ write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
+ break;
+ }
+}
- and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0)));
+static struct lcnphy_unsign16_struct
+wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
+{
+ u16 a, b, didq;
+ u8 di0, dq0, ei, eq, fi, fq;
+ struct lcnphy_unsign16_struct cc;
+ cc.re = 0;
+ cc.im = 0;
+ switch (cal_type) {
+ case 0:
+ wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
+ cc.re = a;
+ cc.im = b;
+ break;
+ case 2:
+ didq = wlc_lcnphy_get_tx_locc(pi);
+ di0 = (((didq & 0xff00) << 16) >> 24);
+ dq0 = (((didq & 0x00ff) << 24) >> 24);
+ cc.re = (u16) di0;
+ cc.im = (u16) dq0;
+ break;
+ case 3:
+ wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
+ cc.re = (u16) ei;
+ cc.im = (u16) eq;
+ break;
+ case 4:
+ wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
+ cc.re = (u16) fi;
+ cc.im = (u16) fq;
+ break;
+ }
+ return cc;
+}
+
+static void
+wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
+ s16 *ptr, int mode)
+{
+ u32 curval1, curval2, stpptr, curptr, strptr, val;
+ u16 sslpnCalibClkEnCtrl, timer;
+ u16 old_sslpnCalibClkEnCtrl;
+ s16 imag, real;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+
+ timer = 0;
+ old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+
+ curval1 = R_REG(&pi->regs->psm_corectlsts);
+ ptr[130] = 0;
+ W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1));
+
+ W_REG(&pi->regs->smpl_clct_strptr, 0x7E00);
+ W_REG(&pi->regs->smpl_clct_stpptr, 0x8000);
+ udelay(20);
+ curval2 = R_REG(&pi->regs->psm_phy_hdr_param);
+ W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30);
+
+ write_phy_reg(pi, 0x555, 0x0);
+ write_phy_reg(pi, 0x5a6, 0x5);
+
+ write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
+ write_phy_reg(pi, 0x5cf, 3);
+ write_phy_reg(pi, 0x5a5, 0x3);
+ write_phy_reg(pi, 0x583, 0x0);
+ write_phy_reg(pi, 0x584, 0x0);
+ write_phy_reg(pi, 0x585, 0x0fff);
+ write_phy_reg(pi, 0x586, 0x0000);
+
+ write_phy_reg(pi, 0x580, 0x4501);
+
+ sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+ write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
+ stpptr = R_REG(&pi->regs->smpl_clct_stpptr);
+ curptr = R_REG(&pi->regs->smpl_clct_curptr);
+ do {
+ udelay(10);
+ curptr = R_REG(&pi->regs->smpl_clct_curptr);
+ timer++;
+ } while ((curptr != stpptr) && (timer < 500));
+
+ W_REG(&pi->regs->psm_phy_hdr_param, 0x2);
+ strptr = 0x7E00;
+ W_REG(&pi->regs->tplatewrptr, strptr);
+ while (strptr < 0x8000) {
+ val = R_REG(&pi->regs->tplatewrdata);
+ imag = ((val >> 16) & 0x3ff);
+ real = ((val) & 0x3ff);
+ if (imag > 511)
+ imag -= 1024;
+
+ if (real > 511)
+ real -= 1024;
+
+ if (pi_lcn->lcnphy_iqcal_swp_dis)
+ ptr[(strptr - 0x7E00) / 4] = real;
+ else
+ ptr[(strptr - 0x7E00) / 4] = imag;
+
+ if (clip_detect_algo) {
+ if (imag > thresh || imag < -thresh) {
+ strptr = 0x8000;
+ ptr[130] = 1;
+ }
+ }
+
+ strptr += 4;
+ }
+
+ write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
+ W_REG(&pi->regs->psm_phy_hdr_param, curval2);
+ W_REG(&pi->regs->psm_corectlsts, curval1);
+}
+
+static void
+wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
+ int step_size_lg2)
+{
+ const struct lcnphy_spb_tone *phy_c1;
+ struct lcnphy_spb_tone phy_c2;
+ struct lcnphy_unsign16_struct phy_c3;
+ int phy_c4, phy_c5, k, l, j, phy_c6;
+ u16 phy_c7, phy_c8, phy_c9;
+ s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
+ s16 *ptr, phy_c17;
+ s32 phy_c18, phy_c19;
+ u32 phy_c20, phy_c21;
+ bool phy_c22, phy_c23, phy_c24, phy_c25;
+ u16 phy_c26, phy_c27;
+ u16 phy_c28, phy_c29, phy_c30;
+ u16 phy_c31;
+ u16 *phy_c32;
+ phy_c21 = 0;
+ phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
+ ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
+ if (NULL == ptr)
+ return;
+
+ phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
+ if (NULL == phy_c32) {
+ kfree(ptr);
+ return;
+ }
+ phy_c26 = read_phy_reg(pi, 0x6da);
+ phy_c27 = read_phy_reg(pi, 0x6db);
+ phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
+ write_phy_reg(pi, 0x93d, 0xC0);
+
+ wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
+ write_phy_reg(pi, 0x6da, 0xffff);
+ or_phy_reg(pi, 0x6db, 0x3);
+
+ wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
+ udelay(500);
+ phy_c28 = read_phy_reg(pi, 0x938);
+ phy_c29 = read_phy_reg(pi, 0x4d7);
+ phy_c30 = read_phy_reg(pi, 0x4d8);
+ or_phy_reg(pi, 0x938, 0x1 << 2);
+ or_phy_reg(pi, 0x4d7, 0x1 << 2);
+ or_phy_reg(pi, 0x4d7, 0x1 << 3);
+ mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
+ or_phy_reg(pi, 0x4d8, 1 << 0);
+ or_phy_reg(pi, 0x4d8, 1 << 1);
+ mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
+ mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
+ phy_c1 = &lcnphy_spb_tone_3750[0];
+ phy_c4 = 32;
+
+ if (num_levels == 0) {
+ if (cal_type != 0)
+ num_levels = 4;
+ else
+ num_levels = 9;
+ }
+ if (step_size_lg2 == 0) {
+ if (cal_type != 0)
+ step_size_lg2 = 3;
+ else
+ step_size_lg2 = 8;
+ }
+
+ phy_c7 = (1 << step_size_lg2);
+ phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
+ phy_c15 = (s16) phy_c3.re;
+ phy_c16 = (s16) phy_c3.im;
+ if (cal_type == 2) {
+ if (phy_c3.re > 127)
+ phy_c15 = phy_c3.re - 256;
+ if (phy_c3.im > 127)
+ phy_c16 = phy_c3.im - 256;
+ }
+ wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
+ udelay(20);
+ for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
+ phy_c23 = 1;
+ phy_c22 = 0;
+ switch (cal_type) {
+ case 0:
+ phy_c10 = 511;
+ break;
+ case 2:
+ phy_c10 = 127;
+ break;
+ case 3:
+ phy_c10 = 15;
+ break;
+ case 4:
+ phy_c10 = 15;
+ break;
+ }
+
+ phy_c9 = read_phy_reg(pi, 0x93d);
+ phy_c9 = 2 * phy_c9;
+ phy_c24 = 0;
+ phy_c5 = 7;
+ phy_c25 = 1;
+ while (1) {
+ write_radio_reg(pi, RADIO_2064_REG026,
+ (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
+ udelay(50);
+ phy_c22 = 0;
+ ptr[130] = 0;
+ wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
+ if (ptr[130] == 1)
+ phy_c22 = 1;
+ if (phy_c22)
+ phy_c5 -= 1;
+ if ((phy_c22 != phy_c24) && (!phy_c25))
+ break;
+ if (!phy_c22)
+ phy_c5 += 1;
+ if (phy_c5 <= 0 || phy_c5 >= 7)
+ break;
+ phy_c24 = phy_c22;
+ phy_c25 = 0;
+ }
+
+ if (phy_c5 < 0)
+ phy_c5 = 0;
+ else if (phy_c5 > 7)
+ phy_c5 = 7;
+
+ for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
+ for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
+ phy_c11 = phy_c15 + k;
+ phy_c12 = phy_c16 + l;
+
+ if (phy_c11 < -phy_c10)
+ phy_c11 = -phy_c10;
+ else if (phy_c11 > phy_c10)
+ phy_c11 = phy_c10;
+ if (phy_c12 < -phy_c10)
+ phy_c12 = -phy_c10;
+ else if (phy_c12 > phy_c10)
+ phy_c12 = phy_c10;
+ wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
+ phy_c12);
+ udelay(20);
+ wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
+
+ phy_c18 = 0;
+ phy_c19 = 0;
+ for (j = 0; j < 128; j++) {
+ if (cal_type != 0)
+ phy_c6 = j % phy_c4;
+ else
+ phy_c6 = (2 * j) % phy_c4;
+
+ phy_c2.re = phy_c1[phy_c6].re;
+ phy_c2.im = phy_c1[phy_c6].im;
+ phy_c17 = ptr[j];
+ phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
+ phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
+ }
+
+ phy_c18 = phy_c18 >> 10;
+ phy_c19 = phy_c19 >> 10;
+ phy_c20 = ((phy_c18 * phy_c18) +
+ (phy_c19 * phy_c19));
+
+ if (phy_c23 || phy_c20 < phy_c21) {
+ phy_c21 = phy_c20;
+ phy_c13 = phy_c11;
+ phy_c14 = phy_c12;
+ }
+ phy_c23 = 0;
+ }
+ }
+ phy_c23 = 1;
+ phy_c15 = phy_c13;
+ phy_c16 = phy_c14;
+ phy_c7 = phy_c7 >> 1;
+ wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
+ udelay(20);
+ }
+ goto cleanup;
+cleanup:
+ wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
+ wlc_lcnphy_stop_tx_tone(pi);
+ write_phy_reg(pi, 0x6da, phy_c26);
+ write_phy_reg(pi, 0x6db, phy_c27);
+ write_phy_reg(pi, 0x938, phy_c28);
+ write_phy_reg(pi, 0x4d7, phy_c29);
+ write_phy_reg(pi, 0x4d8, phy_c30);
+ write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
+
+ kfree(phy_c32);
+ kfree(ptr);
}
void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
@@ -2824,6 +3813,28 @@ void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b)
*b = iqcc[1];
}
+static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
+{
+ struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
+
+ wlc_lcnphy_set_cc(pi, 0, 0, 0);
+ wlc_lcnphy_set_cc(pi, 2, 0, 0);
+ wlc_lcnphy_set_cc(pi, 3, 0, 0);
+ wlc_lcnphy_set_cc(pi, 4, 0, 0);
+
+ wlc_lcnphy_a1(pi, 4, 0, 0);
+ wlc_lcnphy_a1(pi, 3, 0, 0);
+ wlc_lcnphy_a1(pi, 2, 3, 2);
+ wlc_lcnphy_a1(pi, 0, 5, 8);
+ wlc_lcnphy_a1(pi, 2, 2, 1);
+ wlc_lcnphy_a1(pi, 0, 4, 3);
+
+ iqcc0 = wlc_lcnphy_get_cc(pi, 0);
+ locc2 = wlc_lcnphy_get_cc(pi, 2);
+ locc3 = wlc_lcnphy_get_cc(pi, 3);
+ locc4 = wlc_lcnphy_get_cc(pi, 4);
+}
+
u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi)
{
struct phytbl_info tab;
@@ -2878,12 +3889,11 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
lcnphy_recal ? LCNPHY_CAL_RECAL :
LCNPHY_CAL_FULL), false);
} else {
-
wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
}
wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0);
- if ((ABS((s8) fi0) == 15) && (ABS((s8) fq0) == 15)) {
+ if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) {
if (CHSPEC_IS5G(pi->radio_chanspec)) {
target_gains.gm_gain = 255;
target_gains.pga_gain = 255;
@@ -2905,10 +3915,8 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
wlc_lcnphy_tx_iqlo_cal(pi, &target_gains,
LCNPHY_CAL_FULL, false);
} else {
-
wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
}
-
}
wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
@@ -2927,7 +3935,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
wlc_lcnphy_read_table(pi, &tab);
val = (val & 0xfff00000) |
- ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
+ ((u32) (a & 0x3FF) << 10) | (b & 0x3ff);
wlc_lcnphy_write_table(pi, &tab);
val = didq;
@@ -2959,13 +3967,10 @@ s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode)
s16 avg = 0;
bool suspend = 0;
- if (NORADIO_ENAB(pi->pubpi))
- return -1;
-
if (mode == 1) {
suspend =
- (0 ==
- (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ (0 ==
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
@@ -3006,13 +4011,10 @@ u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode)
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- if (NORADIO_ENAB(pi->pubpi))
- return -1;
-
if (mode == 1) {
suspend =
- (0 ==
- (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ (0 ==
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE);
@@ -3063,8 +4065,9 @@ s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode)
{
s32 degree = wlc_lcnphy_tempsense_new(pi, mode);
degree =
- ((degree << 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
- / LCN_TEMPSENSE_DEN;
+ ((degree <<
+ 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1))
+ / LCN_TEMPSENSE_DEN;
return (s8) degree;
}
@@ -3074,13 +4077,10 @@ s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
s32 avg = 0;
bool suspend = 0;
- if (NORADIO_ENAB(pi->pubpi))
- return -1;
-
if (mode == 1) {
suspend =
- (0 ==
- (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ (0 ==
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE);
@@ -3093,9 +4093,8 @@ s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode)
else
avg = (s32) vbatsenseval;
- avg =
- (avg * LCN_VBAT_SCALE_NOM +
- (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
+ avg = (avg * LCN_VBAT_SCALE_NOM +
+ (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN;
if (mode == 1) {
if (!suspend)
@@ -3118,312 +4117,8 @@ static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode)
wlc_lcnphy_toggle_afe_pwdn(pi);
}
-static bool
-wlc_lcnphy_rx_iq_est(struct brcms_phy *pi,
- u16 num_samps,
- u8 wait_time, struct lcnphy_iq_est *iq_est)
-{
- int wait_count = 0;
- bool result = true;
- u8 phybw40;
- phybw40 = CHSPEC_IS40(pi->radio_chanspec);
-
- mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5);
-
- mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3);
-
- mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0);
-
- mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0);
-
- mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8);
-
- mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9);
-
- while (read_phy_reg(pi, 0x481) & (0x1 << 9)) {
-
- if (wait_count > (10 * 500)) {
- result = false;
- goto cleanup;
- }
- udelay(100);
- wait_count++;
- }
-
- iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) |
- (u32) read_phy_reg(pi, 0x484);
- iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) |
- (u32) read_phy_reg(pi, 0x486);
- iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) |
- (u32) read_phy_reg(pi, 0x488);
-
- cleanup:
- mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3);
-
- mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5);
-
- return result;
-}
-
-static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps)
-{
-#define LCNPHY_MIN_RXIQ_PWR 2
- bool result;
- u16 a0_new, b0_new;
- struct lcnphy_iq_est iq_est = { 0, 0, 0 };
- s32 a, b, temp;
- s16 iq_nbits, qq_nbits, arsh, brsh;
- s32 iq;
- u32 ii, qq;
- struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
-
- a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0);
- b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0);
- mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2);
-
- mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6);
-
- wlc_lcnphy_set_rx_iq_comp(pi, 0, 0);
-
- result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est);
- if (!result)
- goto cleanup;
-
- iq = (s32) iq_est.iq_prod;
- ii = iq_est.i_pwr;
- qq = iq_est.q_pwr;
-
- if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) {
- result = false;
- goto cleanup;
- }
-
- iq_nbits = wlc_phy_nbits(iq);
- qq_nbits = wlc_phy_nbits(qq);
-
- arsh = 10 - (30 - iq_nbits);
- if (arsh >= 0) {
- a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
- temp = (s32) (ii >> arsh);
- if (temp == 0) {
- return false;
- }
- } else {
- a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
- temp = (s32) (ii << -arsh);
- if (temp == 0) {
- return false;
- }
- }
- a /= temp;
- brsh = qq_nbits - 31 + 20;
- if (brsh >= 0) {
- b = (qq << (31 - qq_nbits));
- temp = (s32) (ii >> brsh);
- if (temp == 0) {
- return false;
- }
- } else {
- b = (qq << (31 - qq_nbits));
- temp = (s32) (ii << -brsh);
- if (temp == 0) {
- return false;
- }
- }
- b /= temp;
- b -= a * a;
- b = (s32) int_sqrt((unsigned long) b);
- b -= (1 << 10);
- a0_new = (u16) (a & 0x3ff);
- b0_new = (u16) (b & 0x3ff);
- cleanup:
-
- wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new);
-
- mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0);
-
- mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3);
-
- pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new;
- pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new;
-
- return result;
-}
-
-static bool
-wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
- const struct lcnphy_rx_iqcomp *iqcomp,
- int iqcomp_sz, bool tx_switch, bool rx_switch, int module,
- int tx_gain_idx)
-{
- struct lcnphy_txgains old_gains;
- u16 tx_pwr_ctrl;
- u8 tx_gain_index_old = 0;
- bool result = false, tx_gain_override_old = false;
- u16 i, Core1TxControl_old, RFOverride0_old,
- RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
- rfoverride3_old, rfoverride3val_old, rfoverride4_old,
- rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
- int tia_gain;
- u32 received_power, rx_pwr_threshold;
- u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
- u16 values_to_save[11];
- s16 *ptr;
- struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
-
- ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
- if (NULL == ptr) {
- return false;
- }
- if (module == 2) {
- while (iqcomp_sz--) {
- if (iqcomp[iqcomp_sz].chan ==
- CHSPEC_CHANNEL(pi->radio_chanspec)) {
-
- wlc_lcnphy_set_rx_iq_comp(pi,
- (u16)
- iqcomp[iqcomp_sz].a,
- (u16)
- iqcomp[iqcomp_sz].b);
- result = true;
- break;
- }
- }
- goto cal_done;
- }
-
- if (module == 1) {
-
- tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
- wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
-
- for (i = 0; i < 11; i++) {
- values_to_save[i] =
- read_radio_reg(pi, rxiq_cal_rf_reg[i]);
- }
- Core1TxControl_old = read_phy_reg(pi, 0x631);
-
- or_phy_reg(pi, 0x631, 0x0015);
-
- RFOverride0_old = read_phy_reg(pi, 0x44c);
- RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
- rfoverride2_old = read_phy_reg(pi, 0x4b0);
- rfoverride2val_old = read_phy_reg(pi, 0x4b1);
- rfoverride3_old = read_phy_reg(pi, 0x4f9);
- rfoverride3val_old = read_phy_reg(pi, 0x4fa);
- rfoverride4_old = read_phy_reg(pi, 0x938);
- rfoverride4val_old = read_phy_reg(pi, 0x939);
- afectrlovr_old = read_phy_reg(pi, 0x43b);
- afectrlovrval_old = read_phy_reg(pi, 0x43c);
- old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
- old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
-
- tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
- if (tx_gain_override_old) {
- wlc_lcnphy_get_tx_gain(pi, &old_gains);
- tx_gain_index_old = pi_lcn->lcnphy_current_index;
- }
-
- wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
-
- mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
-
- mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
-
- write_radio_reg(pi, RADIO_2064_REG116, 0x06);
- write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
- write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
- write_radio_reg(pi, RADIO_2064_REG098, 0x03);
- write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
- mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
- write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
- write_radio_reg(pi, RADIO_2064_REG114, 0x01);
- write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
- write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
-
- mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
- mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
- mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
- mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
- mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
- mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
- mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
-
- mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
-
- wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
- write_phy_reg(pi, 0x6da, 0xffff);
- or_phy_reg(pi, 0x6db, 0x3);
- wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
- wlc_lcnphy_rx_gain_override_enable(pi, true);
-
- tia_gain = 8;
- rx_pwr_threshold = 950;
- while (tia_gain > 0) {
- tia_gain -= 1;
- wlc_lcnphy_set_rx_gain_by_distribution(pi,
- 0, 0, 2, 2,
- (u16)
- tia_gain, 1, 0);
- udelay(500);
-
- received_power =
- wlc_lcnphy_measure_digital_power(pi, 2000);
- if (received_power < rx_pwr_threshold)
- break;
- }
- result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
-
- wlc_lcnphy_stop_tx_tone(pi);
-
- write_phy_reg(pi, 0x631, Core1TxControl_old);
-
- write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
- write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
- write_phy_reg(pi, 0x4b0, rfoverride2_old);
- write_phy_reg(pi, 0x4b1, rfoverride2val_old);
- write_phy_reg(pi, 0x4f9, rfoverride3_old);
- write_phy_reg(pi, 0x4fa, rfoverride3val_old);
- write_phy_reg(pi, 0x938, rfoverride4_old);
- write_phy_reg(pi, 0x939, rfoverride4val_old);
- write_phy_reg(pi, 0x43b, afectrlovr_old);
- write_phy_reg(pi, 0x43c, afectrlovrval_old);
- write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
- write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
-
- wlc_lcnphy_clear_trsw_override(pi);
-
- mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
-
- for (i = 0; i < 11; i++) {
- write_radio_reg(pi, rxiq_cal_rf_reg[i],
- values_to_save[i]);
- }
-
- if (tx_gain_override_old) {
- wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
- } else
- wlc_lcnphy_disable_tx_gain_override(pi);
- wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
-
- wlc_lcnphy_rx_gain_override_enable(pi, false);
- }
-
- cal_done:
- kfree(ptr);
- return result;
-}
-
static void wlc_lcnphy_temp_adj(struct brcms_phy *pi)
{
- if (NORADIO_ENAB(pi->pubpi))
- return;
}
static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
@@ -3433,7 +4128,7 @@ static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi)
u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
suspend =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
wlc_lcnphy_deaf_mode(pi, true);
@@ -3463,24 +4158,21 @@ static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi)
s32 tssi, pwr, maxtargetpwr, mintargetpwr;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
pi->phy_lastcal = pi->sh->now;
pi->phy_forcecal = false;
full_cal =
- (pi_lcn->lcnphy_full_cal_channel !=
- CHSPEC_CHANNEL(pi->radio_chanspec));
+ (pi_lcn->lcnphy_full_cal_channel !=
+ CHSPEC_CHANNEL(pi->radio_chanspec));
pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
index = pi_lcn->lcnphy_current_index;
suspend =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
if (!suspend) {
-
wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
wlapi_suspend_mac_and_wait(pi->sh->physhim);
}
+
wlc_lcnphy_deaf_mode(pi, true);
wlc_lcnphy_txpwrtbl_iqlo_cal(pi);
@@ -3531,7 +4223,6 @@ void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
switch (mode) {
case PHY_PERICAL_CHAN:
-
break;
case PHY_FULLCAL:
wlc_lcnphy_periodic_cal(pi);
@@ -3558,7 +4249,7 @@ void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode)
case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL:
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
wlc_lcnphy_tx_power_adjustment(
- (struct brcms_phy_pub *) pi);
+ (struct brcms_phy_pub *) pi);
break;
}
}
@@ -3571,7 +4262,7 @@ void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr)
if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) &&
(status & (0x1 << 15))) {
*ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
- >> 0) >> 1);
+ >> 0) >> 1);
if (wlc_phy_tpc_isenabled_lcnphy(pi))
cck_offset = pi->tx_power_offset[TXP_FIRST_CCK];
@@ -3591,59 +4282,6 @@ void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi)
}
-static void
-wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, chanspec_t chanspec)
-{
- u8 channel = CHSPEC_CHANNEL(chanspec);
- struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
-
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
- if (channel == 14) {
- mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8);
-
- } else {
- mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8);
-
- }
- pi_lcn->lcnphy_bandedge_corr = 2;
- if (channel == 1)
- pi_lcn->lcnphy_bandedge_corr = 4;
-
- if (channel == 1 || channel == 2 || channel == 3 ||
- channel == 4 || channel == 9 ||
- channel == 10 || channel == 11 || channel == 12) {
- si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04);
- si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0);
- si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0);
-
- si_pmu_pllupd(pi->sh->sih);
- write_phy_reg(pi, 0x942, 0);
- wlc_lcnphy_txrx_spur_avoidance_mode(pi, false);
- pi_lcn->lcnphy_spurmod = 0;
- mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8);
-
- write_phy_reg(pi, 0x425, 0x5907);
- } else {
- si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04);
- si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333);
- si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820);
-
- si_pmu_pllupd(pi->sh->sih);
- write_phy_reg(pi, 0x942, 0);
- wlc_lcnphy_txrx_spur_avoidance_mode(pi, true);
-
- pi_lcn->lcnphy_spurmod = 0;
- mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8);
-
- write_phy_reg(pi, 0x425, 0x590a);
- }
-
- or_phy_reg(pi, 0x44a, 0x44);
- write_phy_reg(pi, 0x44a, 0x80);
-}
-
void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
{
s8 index;
@@ -3651,570 +4289,21 @@ void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi)
struct brcms_phy *pi = (struct brcms_phy *) ppi;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
- if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && SAVE_txpwrctrl) {
+ if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) &&
+ SAVE_txpwrctrl) {
index = wlc_lcnphy_tempcompensated_txpwrctrl(pi);
index2 = (u16) (index * 2);
mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0);
- pi_lcn->lcnphy_current_index = (s8)
- ((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
- }
-}
-
-static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b)
-{
- mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0);
-
- mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0);
-
- mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0);
-
- mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0);
-
- mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0);
-
- mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0);
-
-}
-
-void wlc_phy_init_lcnphy(struct brcms_phy *pi)
-{
- u8 phybw40;
- struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- phybw40 = CHSPEC_IS40(pi->radio_chanspec);
-
- pi_lcn->lcnphy_cal_counter = 0;
- pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
-
- or_phy_reg(pi, 0x44a, 0x80);
- and_phy_reg(pi, 0x44a, 0x7f);
-
- wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
-
- write_phy_reg(pi, 0x60a, 160);
-
- write_phy_reg(pi, 0x46a, 25);
-
- wlc_lcnphy_baseband_init(pi);
-
- wlc_lcnphy_radio_init(pi);
-
- if (CHSPEC_IS2G(pi->radio_chanspec))
- wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
-
- wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
-
- si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
-
- si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
-
- if ((pi->sh->boardflags & BFL_FEM)
- && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
- wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
-
- wlc_lcnphy_agc_temp_init(pi);
-
- wlc_lcnphy_temp_adj(pi);
-
- mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
-
- udelay(100);
- mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
-
- wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
- pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
- wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
-}
-
-static void
-wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save)
-{
- u16 vmid;
- int i;
- for (i = 0; i < 20; i++) {
- values_to_save[i] =
- read_radio_reg(pi, iqlo_loopback_rf_regs[i]);
- }
-
- mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12);
- mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14);
-
- mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11);
- mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13);
-
- mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
- mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
-
- mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
- mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
-
- if (LCNREV_IS(pi->pubpi.phy_rev, 2))
- and_radio_reg(pi, RADIO_2064_REG03A, 0xFD);
- else
- and_radio_reg(pi, RADIO_2064_REG03A, 0xF9);
- or_radio_reg(pi, RADIO_2064_REG11A, 0x1);
-
- or_radio_reg(pi, RADIO_2064_REG036, 0x01);
- or_radio_reg(pi, RADIO_2064_REG11A, 0x18);
- udelay(20);
-
- if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
- if (CHSPEC_IS5G(pi->radio_chanspec))
- mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0);
- else
- or_radio_reg(pi, RADIO_2064_REG03A, 1);
- } else {
- if (CHSPEC_IS5G(pi->radio_chanspec))
- mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1);
- else
- or_radio_reg(pi, RADIO_2064_REG03A, 0x3);
- }
-
- udelay(20);
-
- write_radio_reg(pi, RADIO_2064_REG025, 0xF);
- if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
- if (CHSPEC_IS5G(pi->radio_chanspec))
- mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4);
- else
- mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6);
- } else {
- if (CHSPEC_IS5G(pi->radio_chanspec))
- mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1);
- else
- mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1);
- }
-
- udelay(20);
-
- write_radio_reg(pi, RADIO_2064_REG005, 0x8);
- or_radio_reg(pi, RADIO_2064_REG112, 0x80);
- udelay(20);
-
- or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
- or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
- udelay(20);
-
- or_radio_reg(pi, RADIO_2064_REG00B, 0x7);
- or_radio_reg(pi, RADIO_2064_REG113, 0x10);
- udelay(20);
-
- write_radio_reg(pi, RADIO_2064_REG007, 0x1);
- udelay(20);
-
- vmid = 0x2A6;
- mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3);
- write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff));
- or_radio_reg(pi, RADIO_2064_REG11F, 0x44);
- udelay(20);
-
- or_radio_reg(pi, RADIO_2064_REG0FF, 0x10);
- udelay(20);
- write_radio_reg(pi, RADIO_2064_REG012, 0x02);
- or_radio_reg(pi, RADIO_2064_REG112, 0x06);
- write_radio_reg(pi, RADIO_2064_REG036, 0x11);
- write_radio_reg(pi, RADIO_2064_REG059, 0xcc);
- write_radio_reg(pi, RADIO_2064_REG05C, 0x2e);
- write_radio_reg(pi, RADIO_2064_REG078, 0xd7);
- write_radio_reg(pi, RADIO_2064_REG092, 0x15);
-}
-
-static void
-wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh,
- s16 *ptr, int mode)
-{
- u32 curval1, curval2, stpptr, curptr, strptr, val;
- u16 sslpnCalibClkEnCtrl, timer;
- u16 old_sslpnCalibClkEnCtrl;
- s16 imag, real;
- struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
-
- timer = 0;
- old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
-
- curval1 = R_REG(&pi->regs->psm_corectlsts);
- ptr[130] = 0;
- W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1));
-
- W_REG(&pi->regs->smpl_clct_strptr, 0x7E00);
- W_REG(&pi->regs->smpl_clct_stpptr, 0x8000);
- udelay(20);
- curval2 = R_REG(&pi->regs->psm_phy_hdr_param);
- W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30);
-
- write_phy_reg(pi, 0x555, 0x0);
- write_phy_reg(pi, 0x5a6, 0x5);
-
- write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6));
- write_phy_reg(pi, 0x5cf, 3);
- write_phy_reg(pi, 0x5a5, 0x3);
- write_phy_reg(pi, 0x583, 0x0);
- write_phy_reg(pi, 0x584, 0x0);
- write_phy_reg(pi, 0x585, 0x0fff);
- write_phy_reg(pi, 0x586, 0x0000);
-
- write_phy_reg(pi, 0x580, 0x4501);
-
- sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
- write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008));
- stpptr = R_REG(&pi->regs->smpl_clct_stpptr);
- curptr = R_REG(&pi->regs->smpl_clct_curptr);
- do {
- udelay(10);
- curptr = R_REG(&pi->regs->smpl_clct_curptr);
- timer++;
- } while ((curptr != stpptr) && (timer < 500));
-
- W_REG(&pi->regs->psm_phy_hdr_param, 0x2);
- strptr = 0x7E00;
- W_REG(&pi->regs->tplatewrptr, strptr);
- while (strptr < 0x8000) {
- val = R_REG(&pi->regs->tplatewrdata);
- imag = ((val >> 16) & 0x3ff);
- real = ((val) & 0x3ff);
- if (imag > 511) {
- imag -= 1024;
- }
- if (real > 511) {
- real -= 1024;
- }
- if (pi_lcn->lcnphy_iqcal_swp_dis)
- ptr[(strptr - 0x7E00) / 4] = real;
- else
- ptr[(strptr - 0x7E00) / 4] = imag;
- if (clip_detect_algo) {
- if (imag > thresh || imag < -thresh) {
- strptr = 0x8000;
- ptr[130] = 1;
- }
- }
- strptr += 4;
- }
-
- write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
- W_REG(&pi->regs->psm_phy_hdr_param, curval2);
- W_REG(&pi->regs->psm_corectlsts, curval1);
-}
-
-static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi)
-{
- struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4;
-
- wlc_lcnphy_set_cc(pi, 0, 0, 0);
- wlc_lcnphy_set_cc(pi, 2, 0, 0);
- wlc_lcnphy_set_cc(pi, 3, 0, 0);
- wlc_lcnphy_set_cc(pi, 4, 0, 0);
-
- wlc_lcnphy_a1(pi, 4, 0, 0);
- wlc_lcnphy_a1(pi, 3, 0, 0);
- wlc_lcnphy_a1(pi, 2, 3, 2);
- wlc_lcnphy_a1(pi, 0, 5, 8);
- wlc_lcnphy_a1(pi, 2, 2, 1);
- wlc_lcnphy_a1(pi, 0, 4, 3);
-
- iqcc0 = wlc_lcnphy_get_cc(pi, 0);
- locc2 = wlc_lcnphy_get_cc(pi, 2);
- locc3 = wlc_lcnphy_get_cc(pi, 3);
- locc4 = wlc_lcnphy_get_cc(pi, 4);
-}
-
-static void
-wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y)
-{
- u16 di0dq0;
- u16 x, y, data_rf;
- int k;
- switch (cal_type) {
- case 0:
- wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y);
- break;
- case 2:
- di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff);
- wlc_lcnphy_set_tx_locc(pi, di0dq0);
- break;
- case 3:
- k = wlc_lcnphy_calc_floor(coeff_x, 0);
- y = 8 + k;
- k = wlc_lcnphy_calc_floor(coeff_x, 1);
- x = 8 - k;
- data_rf = (x * 16 + y);
- write_radio_reg(pi, RADIO_2064_REG089, data_rf);
- k = wlc_lcnphy_calc_floor(coeff_y, 0);
- y = 8 + k;
- k = wlc_lcnphy_calc_floor(coeff_y, 1);
- x = 8 - k;
- data_rf = (x * 16 + y);
- write_radio_reg(pi, RADIO_2064_REG08A, data_rf);
- break;
- case 4:
- k = wlc_lcnphy_calc_floor(coeff_x, 0);
- y = 8 + k;
- k = wlc_lcnphy_calc_floor(coeff_x, 1);
- x = 8 - k;
- data_rf = (x * 16 + y);
- write_radio_reg(pi, RADIO_2064_REG08B, data_rf);
- k = wlc_lcnphy_calc_floor(coeff_y, 0);
- y = 8 + k;
- k = wlc_lcnphy_calc_floor(coeff_y, 1);
- x = 8 - k;
- data_rf = (x * 16 + y);
- write_radio_reg(pi, RADIO_2064_REG08C, data_rf);
- break;
- }
-}
-
-static struct lcnphy_unsign16_struct
-wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type)
-{
- u16 a, b, didq;
- u8 di0, dq0, ei, eq, fi, fq;
- struct lcnphy_unsign16_struct cc;
- cc.re = 0;
- cc.im = 0;
- switch (cal_type) {
- case 0:
- wlc_lcnphy_get_tx_iqcc(pi, &a, &b);
- cc.re = a;
- cc.im = b;
- break;
- case 2:
- didq = wlc_lcnphy_get_tx_locc(pi);
- di0 = (((didq & 0xff00) << 16) >> 24);
- dq0 = (((didq & 0x00ff) << 24) >> 24);
- cc.re = (u16) di0;
- cc.im = (u16) dq0;
- break;
- case 3:
- wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
- cc.re = (u16) ei;
- cc.im = (u16) eq;
- break;
- case 4:
- wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq);
- cc.re = (u16) fi;
- cc.im = (u16) fq;
- break;
- }
- return cc;
-}
-
-static void
-wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels,
- int step_size_lg2)
-{
- const struct lcnphy_spb_tone *phy_c1;
- struct lcnphy_spb_tone phy_c2;
- struct lcnphy_unsign16_struct phy_c3;
- int phy_c4, phy_c5, k, l, j, phy_c6;
- u16 phy_c7, phy_c8, phy_c9;
- s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16;
- s16 *ptr, phy_c17;
- s32 phy_c18, phy_c19;
- u32 phy_c20, phy_c21;
- bool phy_c22, phy_c23, phy_c24, phy_c25;
- u16 phy_c26, phy_c27;
- u16 phy_c28, phy_c29, phy_c30;
- u16 phy_c31;
- u16 *phy_c32;
- phy_c21 = 0;
- phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0;
- ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC);
- if (NULL == ptr) {
- return;
- }
-
- phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC);
- if (NULL == phy_c32) {
- kfree(ptr);
- return;
- }
- phy_c26 = read_phy_reg(pi, 0x6da);
- phy_c27 = read_phy_reg(pi, 0x6db);
- phy_c31 = read_radio_reg(pi, RADIO_2064_REG026);
- write_phy_reg(pi, 0x93d, 0xC0);
-
- wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0);
- write_phy_reg(pi, 0x6da, 0xffff);
- or_phy_reg(pi, 0x6db, 0x3);
-
- wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32);
- udelay(500);
- phy_c28 = read_phy_reg(pi, 0x938);
- phy_c29 = read_phy_reg(pi, 0x4d7);
- phy_c30 = read_phy_reg(pi, 0x4d8);
- or_phy_reg(pi, 0x938, 0x1 << 2);
- or_phy_reg(pi, 0x4d7, 0x1 << 2);
- or_phy_reg(pi, 0x4d7, 0x1 << 3);
- mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12);
- or_phy_reg(pi, 0x4d8, 1 << 0);
- or_phy_reg(pi, 0x4d8, 1 << 1);
- mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2);
- mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12);
- phy_c1 = &lcnphy_spb_tone_3750[0];
- phy_c4 = 32;
-
- if (num_levels == 0) {
- if (cal_type != 0) {
- num_levels = 4;
- } else {
- num_levels = 9;
- }
- }
- if (step_size_lg2 == 0) {
- if (cal_type != 0) {
- step_size_lg2 = 3;
- } else {
- step_size_lg2 = 8;
- }
- }
-
- phy_c7 = (1 << step_size_lg2);
- phy_c3 = wlc_lcnphy_get_cc(pi, cal_type);
- phy_c15 = (s16) phy_c3.re;
- phy_c16 = (s16) phy_c3.im;
- if (cal_type == 2) {
- if (phy_c3.re > 127)
- phy_c15 = phy_c3.re - 256;
- if (phy_c3.im > 127)
- phy_c16 = phy_c3.im - 256;
- }
- wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
- udelay(20);
- for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) {
- phy_c23 = 1;
- phy_c22 = 0;
- switch (cal_type) {
- case 0:
- phy_c10 = 511;
- break;
- case 2:
- phy_c10 = 127;
- break;
- case 3:
- phy_c10 = 15;
- break;
- case 4:
- phy_c10 = 15;
- break;
- }
-
- phy_c9 = read_phy_reg(pi, 0x93d);
- phy_c9 = 2 * phy_c9;
- phy_c24 = 0;
- phy_c5 = 7;
- phy_c25 = 1;
- while (1) {
- write_radio_reg(pi, RADIO_2064_REG026,
- (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4));
- udelay(50);
- phy_c22 = 0;
- ptr[130] = 0;
- wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2);
- if (ptr[130] == 1)
- phy_c22 = 1;
- if (phy_c22)
- phy_c5 -= 1;
- if ((phy_c22 != phy_c24) && (!phy_c25))
- break;
- if (!phy_c22)
- phy_c5 += 1;
- if (phy_c5 <= 0 || phy_c5 >= 7)
- break;
- phy_c24 = phy_c22;
- phy_c25 = 0;
- }
-
- if (phy_c5 < 0)
- phy_c5 = 0;
- else if (phy_c5 > 7)
- phy_c5 = 7;
-
- for (k = -phy_c7; k <= phy_c7; k += phy_c7) {
- for (l = -phy_c7; l <= phy_c7; l += phy_c7) {
- phy_c11 = phy_c15 + k;
- phy_c12 = phy_c16 + l;
-
- if (phy_c11 < -phy_c10)
- phy_c11 = -phy_c10;
- else if (phy_c11 > phy_c10)
- phy_c11 = phy_c10;
- if (phy_c12 < -phy_c10)
- phy_c12 = -phy_c10;
- else if (phy_c12 > phy_c10)
- phy_c12 = phy_c10;
- wlc_lcnphy_set_cc(pi, cal_type, phy_c11,
- phy_c12);
- udelay(20);
- wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2);
-
- phy_c18 = 0;
- phy_c19 = 0;
- for (j = 0; j < 128; j++) {
- if (cal_type != 0) {
- phy_c6 = j % phy_c4;
- } else {
- phy_c6 = (2 * j) % phy_c4;
- }
- phy_c2.re = phy_c1[phy_c6].re;
- phy_c2.im = phy_c1[phy_c6].im;
- phy_c17 = ptr[j];
- phy_c18 = phy_c18 + phy_c17 * phy_c2.re;
- phy_c19 = phy_c19 + phy_c17 * phy_c2.im;
- }
-
- phy_c18 = phy_c18 >> 10;
- phy_c19 = phy_c19 >> 10;
- phy_c20 =
- ((phy_c18 * phy_c18) + (phy_c19 * phy_c19));
-
- if (phy_c23 || phy_c20 < phy_c21) {
- phy_c21 = phy_c20;
- phy_c13 = phy_c11;
- phy_c14 = phy_c12;
- }
- phy_c23 = 0;
- }
- }
- phy_c23 = 1;
- phy_c15 = phy_c13;
- phy_c16 = phy_c14;
- phy_c7 = phy_c7 >> 1;
- wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16);
- udelay(20);
- }
- goto cleanup;
- cleanup:
- wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32);
- wlc_lcnphy_stop_tx_tone(pi);
- write_phy_reg(pi, 0x6da, phy_c26);
- write_phy_reg(pi, 0x6db, phy_c27);
- write_phy_reg(pi, 0x938, phy_c28);
- write_phy_reg(pi, 0x4d7, phy_c29);
- write_phy_reg(pi, 0x4d8, phy_c30);
- write_radio_reg(pi, RADIO_2064_REG026, phy_c31);
-
- kfree(phy_c32);
- kfree(ptr);
-}
-
-static void
-wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save)
-{
- int i;
-
- and_phy_reg(pi, 0x44c, 0x0 >> 11);
-
- and_phy_reg(pi, 0x43b, 0xC);
-
- for (i = 0; i < 20; i++) {
- write_radio_reg(pi, iqlo_loopback_rf_regs[i],
- values_to_save[i]);
+ pi_lcn->lcnphy_current_index =
+ (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2);
}
}
static void
wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
- const struct lcnphy_tx_gain_tbl_entry *gain_table) {
+ const struct lcnphy_tx_gain_tbl_entry *gain_table)
+{
u32 j;
struct phytbl_info tab;
u32 val;
@@ -4297,6 +4386,172 @@ static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi)
}
}
+static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
+{
+ or_phy_reg(pi, 0x805, 0x1);
+
+ mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
+
+ mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
+
+ write_phy_reg(pi, 0x414, 0x1e10);
+ write_phy_reg(pi, 0x415, 0x0640);
+
+ mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
+
+ or_phy_reg(pi, 0x44a, 0x44);
+ write_phy_reg(pi, 0x44a, 0x80);
+ mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
+
+ mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
+
+ if (!(pi->sh->boardrev < 0x1204))
+ mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
+
+ write_phy_reg(pi, 0x7d6, 0x0902);
+ mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
+
+ mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+ mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
+
+ mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
+
+ mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
+
+ mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
+
+ mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
+
+ mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
+ mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
+ mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
+ mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
+ mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
+
+ mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
+
+ wlc_lcnphy_clear_tx_power_offsets(pi);
+ mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
+
+ }
+}
+
+static void wlc_lcnphy_rcal(struct brcms_phy *pi)
+{
+ u8 rcal_value;
+
+ and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
+
+ or_radio_reg(pi, RADIO_2064_REG004, 0x40);
+ or_radio_reg(pi, RADIO_2064_REG120, 0x10);
+
+ or_radio_reg(pi, RADIO_2064_REG078, 0x80);
+ or_radio_reg(pi, RADIO_2064_REG129, 0x02);
+
+ or_radio_reg(pi, RADIO_2064_REG057, 0x01);
+
+ or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
+ mdelay(5);
+ SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
+
+ if (wlc_radio_2064_rcal_done(pi)) {
+ rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
+ rcal_value = rcal_value & 0x1f;
+ }
+
+ and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
+
+ and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
+}
+
+static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
+{
+ u8 dflt_rc_cal_val;
+ u16 flt_val;
+
+ dflt_rc_cal_val = 7;
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1))
+ dflt_rc_cal_val = 11;
+ flt_val =
+ (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
+ (dflt_rc_cal_val);
+ write_phy_reg(pi, 0x933, flt_val);
+ write_phy_reg(pi, 0x934, flt_val);
+ write_phy_reg(pi, 0x935, flt_val);
+ write_phy_reg(pi, 0x936, flt_val);
+ write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
+
+ return;
+}
+
+static void wlc_radio_2064_init(struct brcms_phy *pi)
+{
+ u32 i;
+ const struct lcnphy_radio_regs *lcnphyregs = NULL;
+
+ lcnphyregs = lcnphy_radio_regs_2064;
+
+ for (i = 0; lcnphyregs[i].address != 0xffff; i++)
+ if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
+ write_radio_reg(pi,
+ ((lcnphyregs[i].address & 0x3fff) |
+ RADIO_DEFAULT_CORE),
+ (u16) lcnphyregs[i].init_a);
+ else if (lcnphyregs[i].do_init_g)
+ write_radio_reg(pi,
+ ((lcnphyregs[i].address & 0x3fff) |
+ RADIO_DEFAULT_CORE),
+ (u16) lcnphyregs[i].init_g);
+
+ write_radio_reg(pi, RADIO_2064_REG032, 0x62);
+ write_radio_reg(pi, RADIO_2064_REG033, 0x19);
+
+ write_radio_reg(pi, RADIO_2064_REG090, 0x10);
+
+ write_radio_reg(pi, RADIO_2064_REG010, 0x00);
+
+ if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+
+ write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
+ write_radio_reg(pi, RADIO_2064_REG061, 0x72);
+ write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
+ }
+
+ write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
+ write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
+
+ mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
+
+ write_phy_reg(pi, 0x4ea, 0x4688);
+
+ mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
+
+ mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
+
+ mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
+
+ wlc_lcnphy_set_tx_locc(pi, 0);
+
+ wlc_lcnphy_rcal(pi);
+
+ wlc_lcnphy_rc_cal(pi);
+}
+
+static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
+{
+ wlc_radio_2064_init(pi);
+}
+
static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
{
uint idx;
@@ -4306,9 +4561,8 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
phybw40 = CHSPEC_IS40(pi->radio_chanspec);
- for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) {
+ for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++)
wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]);
- }
if (pi->sh->boardflags & BFL_FEM_BT) {
tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
@@ -4339,39 +4593,35 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
if (CHSPEC_IS2G(pi->radio_chanspec)) {
if (pi->sh->boardflags & BFL_FEM)
- wlc_lcnphy_load_tx_gain_table(pi,
- dot11lcnphy_2GHz_extPA_gaintable_rev0);
+ wlc_lcnphy_load_tx_gain_table(
+ pi,
+ dot11lcnphy_2GHz_extPA_gaintable_rev0);
else
- wlc_lcnphy_load_tx_gain_table(pi,
- dot11lcnphy_2GHz_gaintable_rev0);
+ wlc_lcnphy_load_tx_gain_table(
+ pi,
+ dot11lcnphy_2GHz_gaintable_rev0);
}
if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
+ const struct phytbl_info *tb;
+ int l;
+
if (CHSPEC_IS2G(pi->radio_chanspec)) {
- for (idx = 0;
- idx < dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
- idx++)
- if (pi->sh->boardflags & BFL_EXTLNA)
- wlc_lcnphy_write_table(pi,
- &dot11lcnphytbl_rx_gain_info_extlna_2G_rev2
- [idx]);
- else
- wlc_lcnphy_write_table(pi,
- &dot11lcnphytbl_rx_gain_info_2G_rev2
- [idx]);
+ l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz;
+ if (pi->sh->boardflags & BFL_EXTLNA)
+ tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2;
+ else
+ tb = dot11lcnphytbl_rx_gain_info_2G_rev2;
} else {
- for (idx = 0;
- idx < dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
- idx++)
- if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
- wlc_lcnphy_write_table(pi,
- &dot11lcnphytbl_rx_gain_info_extlna_5G_rev2
- [idx]);
- else
- wlc_lcnphy_write_table(pi,
- &dot11lcnphytbl_rx_gain_info_5G_rev2
- [idx]);
+ l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz;
+ if (pi->sh->boardflags & BFL_EXTLNA_5GHz)
+ tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2;
+ else
+ tb = dot11lcnphytbl_rx_gain_info_5G_rev2;
}
+
+ for (idx = 0; idx < l; idx++)
+ wlc_lcnphy_write_table(pi, &tb[idx]);
}
if ((pi->sh->boardflags & BFL_FEM)
@@ -4379,11 +4629,13 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa);
else if (pi->sh->boardflags & BFL_FEM_BT) {
if (pi->sh->boardrev < 0x1250)
- wlc_lcnphy_write_table(pi,
- &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
+ wlc_lcnphy_write_table(
+ pi,
+ &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa);
else
- wlc_lcnphy_write_table(pi,
- &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
+ wlc_lcnphy_write_table(
+ pi,
+ &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250);
} else
wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313);
@@ -4420,9 +4672,8 @@ static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi)
if (0) {
afectrl1 = 0;
afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) |
- (pi_lcn->lcnphy_rssi_vc << 4) | (pi_lcn->
- lcnphy_rssi_gs
- << 10));
+ (pi_lcn->lcnphy_rssi_vc << 4) |
+ (pi_lcn->lcnphy_rssi_gs << 10));
write_phy_reg(pi, 0x43e, afectrl1);
}
@@ -4443,7 +4694,6 @@ static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi)
{
if (CHSPEC_IS5G(pi->radio_chanspec)) {
mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0);
-
mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8);
}
}
@@ -4455,9 +4705,6 @@ static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
u32 tableBuffer[2];
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
temp = (s16) read_phy_reg(pi, 0x4df);
pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0;
@@ -4484,18 +4731,15 @@ static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
tableBuffer[1] -= 128;
pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1];
- temp = (s16) (read_phy_reg(pi, 0x434)
- & (0xff << 0));
+ temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0));
if (temp > 127)
temp -= 256;
pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp;
- pi_lcn->lcnphy_Med_Low_Gain_db = (read_phy_reg(pi, 0x424)
- & (0xff << 8))
- >> 8;
- pi_lcn->lcnphy_Very_Low_Gain_db = (read_phy_reg(pi, 0x425)
- & (0xff << 0))
- >> 0;
+ pi_lcn->lcnphy_Med_Low_Gain_db =
+ (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8;
+ pi_lcn->lcnphy_Very_Low_Gain_db =
+ (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0;
tab.tbl_ptr = tableBuffer;
tab.tbl_len = 2;
@@ -4509,61 +4753,6 @@ static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi)
}
-static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi)
-{
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
- or_phy_reg(pi, 0x805, 0x1);
-
- mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0);
-
- mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0);
-
- write_phy_reg(pi, 0x414, 0x1e10);
- write_phy_reg(pi, 0x415, 0x0640);
-
- mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8);
-
- or_phy_reg(pi, 0x44a, 0x44);
- write_phy_reg(pi, 0x44a, 0x80);
- mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0);
-
- mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0);
-
- if (!(pi->sh->boardrev < 0x1204))
- mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0);
-
- write_phy_reg(pi, 0x7d6, 0x0902);
- mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0);
-
- mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4);
-
- if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
- mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0);
-
- mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0);
-
- mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0);
-
- mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0);
-
- mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2);
-
- mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4);
- mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0);
- mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90);
- mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2);
- mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0);
-
- mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2);
-
- wlc_lcnphy_clear_tx_power_offsets(pi);
- mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6);
-
- }
-}
-
static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
{
@@ -4574,127 +4763,53 @@ static void wlc_lcnphy_baseband_init(struct brcms_phy *pi)
wlc_lcnphy_bu_tweaks(pi);
}
-static void wlc_radio_2064_init(struct brcms_phy *pi)
+void wlc_phy_init_lcnphy(struct brcms_phy *pi)
{
- u32 i;
- struct lcnphy_radio_regs *lcnphyregs = NULL;
-
- lcnphyregs = lcnphy_radio_regs_2064;
-
- for (i = 0; lcnphyregs[i].address != 0xffff; i++)
- if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a)
- write_radio_reg(pi,
- ((lcnphyregs[i].address & 0x3fff) |
- RADIO_DEFAULT_CORE),
- (u16) lcnphyregs[i].init_a);
- else if (lcnphyregs[i].do_init_g)
- write_radio_reg(pi,
- ((lcnphyregs[i].address & 0x3fff) |
- RADIO_DEFAULT_CORE),
- (u16) lcnphyregs[i].init_g);
-
- write_radio_reg(pi, RADIO_2064_REG032, 0x62);
- write_radio_reg(pi, RADIO_2064_REG033, 0x19);
-
- write_radio_reg(pi, RADIO_2064_REG090, 0x10);
-
- write_radio_reg(pi, RADIO_2064_REG010, 0x00);
-
- if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
-
- write_radio_reg(pi, RADIO_2064_REG060, 0x7f);
- write_radio_reg(pi, RADIO_2064_REG061, 0x72);
- write_radio_reg(pi, RADIO_2064_REG062, 0x7f);
- }
-
- write_radio_reg(pi, RADIO_2064_REG01D, 0x02);
- write_radio_reg(pi, RADIO_2064_REG01E, 0x06);
-
- mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0);
-
- mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3);
-
- mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6);
-
- mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9);
-
- mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12);
-
- write_phy_reg(pi, 0x4ea, 0x4688);
-
- mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
-
- mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
-
- mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0);
-
- wlc_lcnphy_set_tx_locc(pi, 0);
-
- wlc_lcnphy_rcal(pi);
+ u8 phybw40;
+ struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ phybw40 = CHSPEC_IS40(pi->radio_chanspec);
- wlc_lcnphy_rc_cal(pi);
-}
+ pi_lcn->lcnphy_cal_counter = 0;
+ pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense;
-static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
-{
- if (NORADIO_ENAB(pi->pubpi))
- return;
+ or_phy_reg(pi, 0x44a, 0x80);
+ and_phy_reg(pi, 0x44a, 0x7f);
- wlc_radio_2064_init(pi);
-}
+ wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X);
-static void wlc_lcnphy_rcal(struct brcms_phy *pi)
-{
- u8 rcal_value;
+ write_phy_reg(pi, 0x60a, 160);
- if (NORADIO_ENAB(pi->pubpi))
- return;
+ write_phy_reg(pi, 0x46a, 25);
- and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
+ wlc_lcnphy_baseband_init(pi);
- or_radio_reg(pi, RADIO_2064_REG004, 0x40);
- or_radio_reg(pi, RADIO_2064_REG120, 0x10);
+ wlc_lcnphy_radio_init(pi);
- or_radio_reg(pi, RADIO_2064_REG078, 0x80);
- or_radio_reg(pi, RADIO_2064_REG129, 0x02);
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi);
- or_radio_reg(pi, RADIO_2064_REG057, 0x01);
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
- or_radio_reg(pi, RADIO_2064_REG05B, 0x02);
- mdelay(5);
- SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000);
+ si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9);
- if (wlc_radio_2064_rcal_done(pi)) {
- rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C);
- rcal_value = rcal_value & 0x1f;
- }
+ si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD);
- and_radio_reg(pi, RADIO_2064_REG05B, 0xfD);
+ if ((pi->sh->boardflags & BFL_FEM)
+ && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
+ wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR);
- and_radio_reg(pi, RADIO_2064_REG057, 0xFE);
-}
+ wlc_lcnphy_agc_temp_init(pi);
-static void wlc_lcnphy_rc_cal(struct brcms_phy *pi)
-{
- u8 dflt_rc_cal_val;
- u16 flt_val;
+ wlc_lcnphy_temp_adj(pi);
- if (NORADIO_ENAB(pi->pubpi))
- return;
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14);
- dflt_rc_cal_val = 7;
- if (LCNREV_IS(pi->pubpi.phy_rev, 1))
- dflt_rc_cal_val = 11;
- flt_val =
- (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) |
- (dflt_rc_cal_val);
- write_phy_reg(pi, 0x933, flt_val);
- write_phy_reg(pi, 0x934, flt_val);
- write_phy_reg(pi, 0x935, flt_val);
- write_phy_reg(pi, 0x936, flt_val);
- write_phy_reg(pi, 0x937, (flt_val & 0x1FF));
+ udelay(100);
+ mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14);
- return;
+ wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW);
+ pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT;
+ wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT);
}
static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
@@ -4702,39 +4817,38 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
s8 txpwr = 0;
int i;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
+ struct phy_shim_info *shim = pi->sh->physhim;
if (CHSPEC_IS2G(pi->radio_chanspec)) {
u16 cckpo = 0;
u32 offset_ofdm, offset_mcs;
pi_lcn->lcnphy_tr_isolation_mid =
- (u8) PHY_GETINTVAR(pi, "triso2g");
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
pi_lcn->lcnphy_rx_power_offset =
- (u8) PHY_GETINTVAR(pi, "rxpo2g");
-
- pi->txpa_2g[0] = (s16) PHY_GETINTVAR(pi, "pa0b0");
- pi->txpa_2g[1] = (s16) PHY_GETINTVAR(pi, "pa0b1");
- pi->txpa_2g[2] = (s16) PHY_GETINTVAR(pi, "pa0b2");
-
- pi_lcn->lcnphy_rssi_vf = (u8) PHY_GETINTVAR(pi, "rssismf2g");
- pi_lcn->lcnphy_rssi_vc = (u8) PHY_GETINTVAR(pi, "rssismc2g");
- pi_lcn->lcnphy_rssi_gs = (u8) PHY_GETINTVAR(pi, "rssisav2g");
-
- {
- pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
- pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
- pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
-
- pi_lcn->lcnphy_rssi_vf_hightemp =
- pi_lcn->lcnphy_rssi_vf;
- pi_lcn->lcnphy_rssi_vc_hightemp =
- pi_lcn->lcnphy_rssi_vc;
- pi_lcn->lcnphy_rssi_gs_hightemp =
- pi_lcn->lcnphy_rssi_gs;
- }
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G);
+
+ pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0);
+ pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1);
+ pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2);
- txpwr = (s8) PHY_GETINTVAR(pi, "maxp2ga0");
+ pi_lcn->lcnphy_rssi_vf =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G);
+ pi_lcn->lcnphy_rssi_vc =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G);
+ pi_lcn->lcnphy_rssi_gs =
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G);
+
+ pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
+ pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
+ pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs;
+
+ pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf;
+ pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
+ pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
+
+ txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0);
pi->tx_srom_max_2g = txpwr;
for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
@@ -4742,79 +4856,72 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
}
- cckpo = (u16) PHY_GETINTVAR(pi, "cck2gpo");
+ cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO);
+ offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO);
if (cckpo) {
uint max_pwr_chan = txpwr;
for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
- pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
- ((cckpo & 0xf) * 2);
+ pi->tx_srom_max_rate_2g[i] =
+ max_pwr_chan - ((cckpo & 0xf) * 2);
cckpo >>= 4;
}
- offset_ofdm = (u32) PHY_GETINTVAR(pi, "ofdm2gpo");
for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
- pi->tx_srom_max_rate_2g[i] = max_pwr_chan -
- ((offset_ofdm & 0xf) * 2);
+ pi->tx_srom_max_rate_2g[i] =
+ max_pwr_chan -
+ ((offset_ofdm & 0xf) * 2);
offset_ofdm >>= 4;
}
} else {
u8 opo = 0;
- opo = (u8) PHY_GETINTVAR(pi, "opo");
+ opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO);
- for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) {
+ for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
pi->tx_srom_max_rate_2g[i] = txpwr;
- }
-
- offset_ofdm = (u32) PHY_GETINTVAR(pi, "ofdm2gpo");
for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) {
pi->tx_srom_max_rate_2g[i] = txpwr -
- ((offset_ofdm & 0xf) * 2);
+ ((offset_ofdm & 0xf) * 2);
offset_ofdm >>= 4;
}
offset_mcs =
- ((u16) PHY_GETINTVAR(pi, "mcs2gpo1") << 16) |
- (u16) PHY_GETINTVAR(pi, "mcs2gpo0");
+ wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO1) << 16;
+ offset_mcs |=
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO0);
pi_lcn->lcnphy_mcs20_po = offset_mcs;
for (i = TXP_FIRST_SISO_MCS_20;
i <= TXP_LAST_SISO_MCS_20; i++) {
pi->tx_srom_max_rate_2g[i] =
- txpwr - ((offset_mcs & 0xf) * 2);
+ txpwr - ((offset_mcs & 0xf) * 2);
offset_mcs >>= 4;
}
}
pi_lcn->lcnphy_rawtempsense =
- (u16) PHY_GETINTVAR(pi, "rawtempsense");
+ (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE);
pi_lcn->lcnphy_measPower =
- (u8) PHY_GETINTVAR(pi, "measpower");
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER);
pi_lcn->lcnphy_tempsense_slope =
- (u8) PHY_GETINTVAR(pi, "tempsense_slope");
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE);
pi_lcn->lcnphy_hw_iqcal_en =
- (bool) PHY_GETINTVAR(pi, "hw_iqcal_en");
+ (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN);
pi_lcn->lcnphy_iqcal_swp_dis =
- (bool) PHY_GETINTVAR(pi, "iqcal_swp_dis");
+ (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS);
pi_lcn->lcnphy_tempcorrx =
- (u8) PHY_GETINTVAR(pi, "tempcorrx");
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX);
pi_lcn->lcnphy_tempsense_option =
- (u8) PHY_GETINTVAR(pi, "tempsense_option");
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION);
pi_lcn->lcnphy_freqoffset_corr =
- (u8) PHY_GETINTVAR(pi, "freqoffset_corr");
- if ((u8) getintvar(pi->vars, "aa2g") > 1)
+ (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR);
+ if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1)
wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
- (u8) getintvar(pi->vars,
- "aa2g"));
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G));
}
pi_lcn->lcnphy_cck_dig_filt_type = -1;
- if (PHY_GETVAR(pi, "cckdigfilttype")) {
- s16 temp;
- temp = (s16) PHY_GETINTVAR(pi, "cckdigfilttype");
- if (temp >= 0) {
- pi_lcn->lcnphy_cck_dig_filt_type = temp;
- }
- }
return true;
}
@@ -4834,172 +4941,6 @@ void wlc_2064_vco_cal(struct brcms_phy *pi)
mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0);
}
-static void
-wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
-{
- uint i;
- const struct chan_info_2064_lcnphy *ci;
- u8 rfpll_doubler = 0;
- u8 pll_pwrup, pll_pwrup_ovr;
- fixed qFxtal, qFref, qFvco, qFcal;
- u8 d15, d16, f16, e44, e45;
- u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div;
- u16 loop_bw, d30, setCount;
- if (NORADIO_ENAB(pi->pubpi))
- return;
- ci = &chan_info_2064_lcnphy[0];
- rfpll_doubler = 1;
-
- mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2);
-
- write_radio_reg(pi, RADIO_2064_REG09E, 0xf);
- if (!rfpll_doubler) {
- loop_bw = PLL_2064_LOOP_BW;
- d30 = PLL_2064_D30;
- } else {
- loop_bw = PLL_2064_LOOP_BW_DOUBLER;
- d30 = PLL_2064_D30_DOUBLER;
- }
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++)
- if (chan_info_2064_lcnphy[i].chan == channel)
- break;
-
- if (i >= ARRAY_SIZE(chan_info_2064_lcnphy)) {
- return;
- }
-
- ci = &chan_info_2064_lcnphy[i];
- }
-
- write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune);
-
- mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx);
-
- mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl);
-
- mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g);
-
- mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2,
- (ci->logen_rccr_rx) << 2);
-
- mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune);
-
- mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4,
- (ci->pa_rxrf_lna2_freq_tune) << 4);
-
- write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1);
-
- pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044);
- pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B);
-
- or_radio_reg(pi, RADIO_2064_REG044, 0x07);
-
- or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1);
- e44 = 0;
- e45 = 0;
-
- fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq);
- if (pi->xtalfreq > 26000000)
- e44 = 1;
- if (pi->xtalfreq > 52000000)
- e45 = 1;
- if (e44 == 0)
- fcal_div = 1;
- else if (e45 == 0)
- fcal_div = 2;
- else
- fcal_div = 4;
- fvco3 = (ci->freq * 3);
- fref3 = 2 * fpfd;
-
- qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16);
- qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16);
- qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ;
- qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16);
-
- write_radio_reg(pi, RADIO_2064_REG04F, 0x02);
-
- d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1;
- write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2)));
- write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5);
-
- d16 = (qFcal * 8 / (d15 + 1)) - 1;
- write_radio_reg(pi, RADIO_2064_REG051, d16);
-
- f16 = ((d16 + 1) * (d15 + 1)) / qFcal;
- setCount = f16 * 3 * (ci->freq) / 32 - 1;
- mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0),
- (u8) (setCount >> 8));
-
- or_radio_reg(pi, RADIO_2064_REG053, 0x10);
- write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff));
-
- div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4;
-
- div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4;
- while (div_frac >= fref3) {
- div_int++;
- div_frac -= fref3;
- }
- div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20);
-
- mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0),
- (u8) (div_int >> 4));
- mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4),
- (u8) (div_int << 4));
- mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0),
- (u8) (div_frac >> 16));
- write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff);
- write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff);
-
- write_radio_reg(pi, RADIO_2064_REG040, 0xfb);
-
- write_radio_reg(pi, RADIO_2064_REG041, 0x9A);
- write_radio_reg(pi, RADIO_2064_REG042, 0xA3);
- write_radio_reg(pi, RADIO_2064_REG043, 0x0C);
-
- {
- u8 h29, h23, c28, d29, h28_ten, e30, h30_ten, cp_current;
- u16 c29, c38, c30, g30, d28;
- c29 = loop_bw;
- d29 = 200;
- c38 = 1250;
- h29 = d29 / c29;
- h23 = 1;
- c28 = 30;
- d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) *
- (fvco3 / 2 - PLL_2064_LOW_END_VCO)) /
- (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO))
- + PLL_2064_LOW_END_KVCO;
- h28_ten = (d28 * 10) / c28;
- c30 = 2640;
- e30 = (d30 - 680) / 490;
- g30 = 680 + (e30 * 490);
- h30_ten = (g30 * 10) / c30;
- cp_current = ((c38 * h29 * h23 * 100) / h28_ten) / h30_ten;
- mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current);
- }
- if (channel >= 1 && channel <= 5)
- write_radio_reg(pi, RADIO_2064_REG03C, 0x8);
- else
- write_radio_reg(pi, RADIO_2064_REG03C, 0x7);
- write_radio_reg(pi, RADIO_2064_REG03D, 0x3);
-
- mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c);
- udelay(1);
-
- wlc_2064_vco_cal(pi);
-
- write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup);
- write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr);
- if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
- write_radio_reg(pi, RADIO_2064_REG038, 3);
- write_radio_reg(pi, RADIO_2064_REG091, 7);
- }
-}
-
bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi)
{
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi))
@@ -5015,14 +4956,11 @@ void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi)
if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) {
wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL);
} else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) {
-
pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
wlc_lcnphy_txpower_recalc_target(pi);
-
wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl);
- } else
- return;
+ }
}
void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
@@ -5035,13 +4973,12 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
struct brcms_phy_lcnphy *pi_lcn;
pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC);
- if (pi->u.pi_lcnphy == NULL) {
+ if (pi->u.pi_lcnphy == NULL)
return false;
- }
pi_lcn = pi->u.pi_lcnphy;
- if ((0 == (pi->sh->boardflags & BFL_NOPA)) && !NORADIO_ENAB(pi->pubpi)) {
+ if (0 == (pi->sh->boardflags & BFL_NOPA)) {
pi->hwpwrctrl = true;
pi->hwpwrctrl_capable = true;
}
@@ -5062,7 +4999,8 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
return false;
- if ((pi->sh->boardflags & BFL_FEM) && (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
+ if ((pi->sh->boardflags & BFL_FEM) &&
+ (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
if (pi_lcn->lcnphy_tempsense_option == 3) {
pi->hwpwrctrl = true;
pi->hwpwrctrl_capable = true;
@@ -5090,8 +5028,8 @@ static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain)
biq1 = (u16) (gain >> 16) & 0xf;
gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) |
- ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
- ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
+ ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) |
+ ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12));
gain16_19 = biq1;
mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0);
@@ -5126,18 +5064,19 @@ static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index)
lcnphy_23bitgaincode_table
[*gain_index]);
received_power =
- wlc_lcnphy_measure_digital_power(pi,
- pi_lcn->
- lcnphy_noise_samples);
+ wlc_lcnphy_measure_digital_power(
+ pi,
+ pi_lcn->
+ lcnphy_noise_samples);
(*gain_index)++;
}
(*gain_index)--;
} else {
wlc_lcnphy_set_rx_gain(pi, gain_code);
received_power =
- wlc_lcnphy_measure_digital_power(pi,
- pi_lcn->
- lcnphy_noise_samples);
+ wlc_lcnphy_measure_digital_power(pi,
+ pi_lcn->
+ lcnphy_noise_samples);
}
return received_power;
@@ -5150,6 +5089,8 @@ s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
s32 log_val, gain_mismatch, desired_gain, input_power_offset_db,
input_power_db;
s32 received_power, temperature;
+ u32 power;
+ u32 msb1, msb2, val1, val2, diff1, diff2;
uint freq;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
@@ -5159,20 +5100,17 @@ s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
nominal_power_db = read_phy_reg(pi, 0x425) >> 8;
- {
- u32 power = (received_power * 16);
- u32 msb1, msb2, val1, val2, diff1, diff2;
- msb1 = ffs(power) - 1;
- msb2 = msb1 + 1;
- val1 = 1 << msb1;
- val2 = 1 << msb2;
- diff1 = (power - val1);
- diff2 = (val2 - power);
- if (diff1 < diff2)
- log_val = msb1;
- else
- log_val = msb2;
- }
+ power = (received_power * 16);
+ msb1 = ffs(power) - 1;
+ msb2 = msb1 + 1;
+ val1 = 1 << msb1;
+ val2 = 1 << msb2;
+ diff1 = (power - val1);
+ diff2 = (val2 - power);
+ if (diff1 < diff2)
+ log_val = msb1;
+ else
+ log_val = msb2;
log_val = log_val * 3;
@@ -5188,7 +5126,7 @@ s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
input_power_db = input_power_offset_db - desired_gain;
input_power_db =
- input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
+ input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index];
freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec));
if ((freq > 2427) && (freq <= 2467))
@@ -5196,99 +5134,21 @@ s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index)
temperature = pi_lcn->lcnphy_lastsensed_temperature;
- if ((temperature - 15) < -30) {
+ if ((temperature - 15) < -30)
input_power_db =
- input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
- 7;
- } else if ((temperature - 15) < 4) {
+ input_power_db +
+ (((temperature - 10 - 25) * 286) >> 12) -
+ 7;
+ else if ((temperature - 15) < 4)
input_power_db =
- input_power_db + (((temperature - 10 - 25) * 286) >> 12) -
- 3;
- } else {
- input_power_db =
- input_power_db + (((temperature - 10 - 25) * 286) >> 12);
- }
+ input_power_db +
+ (((temperature - 10 - 25) * 286) >> 12) -
+ 3;
+ else
+ input_power_db = input_power_db +
+ (((temperature - 10 - 25) * 286) >> 12);
wlc_lcnphy_rx_gain_override_enable(pi, 0);
return input_power_db;
}
-
-static int
-wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type)
-{
- s16 filt_index = -1;
- int j;
-
- u16 addr[] = {
- 0x910,
- 0x91e,
- 0x91f,
- 0x924,
- 0x925,
- 0x926,
- 0x920,
- 0x921,
- 0x927,
- 0x928,
- 0x929,
- 0x922,
- 0x923,
- 0x930,
- 0x931,
- 0x932
- };
-
- u16 addr_ofdm[] = {
- 0x90f,
- 0x900,
- 0x901,
- 0x906,
- 0x907,
- 0x908,
- 0x902,
- 0x903,
- 0x909,
- 0x90a,
- 0x90b,
- 0x904,
- 0x905,
- 0x90c,
- 0x90d,
- 0x90e
- };
-
- if (!is_ofdm) {
- for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) {
- if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) {
- filt_index = (s16) j;
- break;
- }
- }
-
- if (filt_index != -1) {
- for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, addr[j],
- LCNPHY_txdigfiltcoeffs_cck
- [filt_index][j + 1]);
- }
- }
- } else {
- for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) {
- if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) {
- filt_index = (s16) j;
- break;
- }
- }
-
- if (filt_index != -1) {
- for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, addr_ofdm[j],
- LCNPHY_txdigfiltcoeffs_ofdm
- [filt_index][j + 1]);
- }
- }
- }
-
- return (filt_index != -1) ? 0 : -1;
-}
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_n.c b/drivers/staging/brcm80211/brcmsmac/phy/phy_n.c
index f8e419239425..cd19c2f7a347 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_n.c
@@ -14,7 +14,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/kernel.h>
#include <linux/delay.h>
+#include <linux/cordic.h>
#include <brcm_hw_ids.h>
#include <aiutils.h>
@@ -28,27 +30,42 @@
#include "phyreg_n.h"
#include "phytbl_n.h"
-#define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name) \
- read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
- ((core == PHY_CORE_0) ? radio_type##_##jspace##0 : radio_type##_##jspace##1))
-#define WRITE_RADIO_REG2(pi, radio_type, jspace, core, reg_name, value) \
+#define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name) \
+ read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
+ ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0 : \
+ radio_type##_##jspace##1))
+
+#define WRITE_RADIO_REG2(pi, radio_type, jspace, core, reg_name, value) \
write_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
- ((core == PHY_CORE_0) ? radio_type##_##jspace##0 : radio_type##_##jspace##1), value);
-#define WRITE_RADIO_SYN(pi, radio_type, reg_name, value) \
- write_radio_reg(pi, radio_type##_##SYN##_##reg_name, value);
-
-#define READ_RADIO_REG3(pi, radio_type, jspace, core, reg_name) \
- read_radio_reg(pi, ((core == PHY_CORE_0) ? radio_type##_##jspace##0##_##reg_name : \
- radio_type##_##jspace##1##_##reg_name));
-#define WRITE_RADIO_REG3(pi, radio_type, jspace, core, reg_name, value) \
- write_radio_reg(pi, ((core == PHY_CORE_0) ? radio_type##_##jspace##0##_##reg_name : \
- radio_type##_##jspace##1##_##reg_name), value);
-#define READ_RADIO_REG4(pi, radio_type, jspace, core, reg_name) \
- read_radio_reg(pi, ((core == PHY_CORE_0) ? radio_type##_##reg_name##_##jspace##0 : \
- radio_type##_##reg_name##_##jspace##1));
-#define WRITE_RADIO_REG4(pi, radio_type, jspace, core, reg_name, value) \
- write_radio_reg(pi, ((core == PHY_CORE_0) ? radio_type##_##reg_name##_##jspace##0 : \
- radio_type##_##reg_name##_##jspace##1), value);
+ ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0 : \
+ radio_type##_##jspace##1), value)
+
+#define WRITE_RADIO_SYN(pi, radio_type, reg_name, value) \
+ write_radio_reg(pi, radio_type##_##SYN##_##reg_name, value)
+
+#define READ_RADIO_REG3(pi, radio_type, jspace, core, reg_name) \
+ read_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0##_##reg_name : \
+ radio_type##_##jspace##1##_##reg_name))
+
+#define WRITE_RADIO_REG3(pi, radio_type, jspace, core, reg_name, value) \
+ write_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##jspace##0##_##reg_name : \
+ radio_type##_##jspace##1##_##reg_name), \
+ value)
+
+#define READ_RADIO_REG4(pi, radio_type, jspace, core, reg_name) \
+ read_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##reg_name##_##jspace##0 : \
+ radio_type##_##reg_name##_##jspace##1))
+
+#define WRITE_RADIO_REG4(pi, radio_type, jspace, core, reg_name, value) \
+ write_radio_reg(pi, ((core == PHY_CORE_0) ? \
+ radio_type##_##reg_name##_##jspace##0 : \
+ radio_type##_##reg_name##_##jspace##1), \
+ value)
#define NPHY_ACI_MAX_UNDETECT_WINDOW_SZ 40
#define NPHY_ACI_CHANNEL_DELTA 5
@@ -103,9 +120,11 @@
#define NPHY_CALSANITY_RSSI_NB_MAX_POS 9
#define NPHY_CALSANITY_RSSI_NB_MAX_NEG -9
#define NPHY_CALSANITY_RSSI_W1_MAX_POS 12
-#define NPHY_CALSANITY_RSSI_W1_MAX_NEG (NPHY_RSSICAL_W1_TARGET - NPHY_RSSICAL_MAXREAD)
+#define NPHY_CALSANITY_RSSI_W1_MAX_NEG (NPHY_RSSICAL_W1_TARGET - \
+ NPHY_RSSICAL_MAXREAD)
#define NPHY_CALSANITY_RSSI_W2_MAX_POS NPHY_CALSANITY_RSSI_W1_MAX_POS
-#define NPHY_CALSANITY_RSSI_W2_MAX_NEG (NPHY_RSSICAL_W2_TARGET - NPHY_RSSICAL_MAXREAD)
+#define NPHY_CALSANITY_RSSI_W2_MAX_NEG (NPHY_RSSICAL_W2_TARGET - \
+ NPHY_RSSICAL_MAXREAD)
#define NPHY_RSSI_SXT(x) ((s8) (-((x) & 0x20) + ((x) & 0x1f)))
#define NPHY_RSSI_NB_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_NB_MAX_POS) || \
((x) < NPHY_CALSANITY_RSSI_NB_MAX_NEG))
@@ -124,11 +143,11 @@
#define NPHY_PAPD_COMP_OFF 0
#define NPHY_PAPD_COMP_ON 1
-#define NPHY_SROM_TEMPSHIFT 32
-#define NPHY_SROM_MAXTEMPOFFSET 16
-#define NPHY_SROM_MINTEMPOFFSET -16
+#define NPHY_SROM_TEMPSHIFT 32
+#define NPHY_SROM_MAXTEMPOFFSET 16
+#define NPHY_SROM_MINTEMPOFFSET -16
-#define NPHY_CAL_MAXTEMPDELTA 64
+#define NPHY_CAL_MAXTEMPDELTA 64
#define NPHY_NOISEVAR_TBLLEN40 256
#define NPHY_NOISEVAR_TBLLEN20 128
@@ -138,8 +157,24 @@
#define NPHY_ADJUSTED_MINCRSPOWER 0x1e
/* 5357 Chip specific ChipControl register bits */
-#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */
-#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */
+#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */
+#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */
+
+#define NPHY_CAL_TSSISAMPS 64
+#define NPHY_TEST_TONE_FREQ_40MHz 4000
+#define NPHY_TEST_TONE_FREQ_20MHz 2500
+
+#define MAX_205x_RCAL_WAITLOOPS 10000
+
+#define NPHY_RXCAL_TONEAMP 181
+#define NPHY_RXCAL_TONEFREQ_40MHz 4000
+#define NPHY_RXCAL_TONEFREQ_20MHz 2000
+
+#define TXFILT_SHAPING_OFDM20 0
+#define TXFILT_SHAPING_OFDM40 1
+#define TXFILT_SHAPING_CCK 2
+#define TXFILT_DEFAULT_OFDM20 3
+#define TXFILT_DEFAULT_OFDM40 4
struct nphy_iqcal_params {
u16 txlpf;
@@ -184,44 +219,42 @@ struct nphy_ipa_txrxgain {
#define NPHY_IPA_RXCAL_MAXGAININDEX (6 - 1)
-struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz[] = { {0, 0, 0, 0, 0, 100},
-{0, 0, 0, 0, 0, 50},
-{0, 0, 0, 0, 0, -1},
-{0, 0, 0, 3, 0, -1},
-{0, 0, 3, 3, 0, -1},
-{0, 2, 3, 3, 0, -1}
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz[] = {
+ {0, 0, 0, 0, 0, 100},
+ {0, 0, 0, 0, 0, 50},
+ {0, 0, 0, 0, 0, -1},
+ {0, 0, 0, 3, 0, -1},
+ {0, 0, 3, 3, 0, -1},
+ {0, 2, 3, 3, 0, -1}
};
-struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz[] = { {0, 0, 0, 0, 0, 128},
-{0, 0, 0, 0, 0, 70},
-{0, 0, 0, 0, 0, 20},
-{0, 0, 0, 3, 0, 20},
-{0, 0, 3, 3, 0, 20},
-{0, 2, 3, 3, 0, 20}
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz[] = {
+ {0, 0, 0, 0, 0, 128},
+ {0, 0, 0, 0, 0, 70},
+ {0, 0, 0, 0, 0, 20},
+ {0, 0, 0, 3, 0, 20},
+ {0, 0, 3, 3, 0, 20},
+ {0, 2, 3, 3, 0, 20}
};
-struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz_rev7[] = {
-{0, 0, 0, 0, 0, 100},
-{0, 0, 0, 0, 0, 50},
-{0, 0, 0, 0, 0, -1},
-{0, 0, 0, 3, 0, -1},
-{0, 0, 3, 3, 0, -1},
-{0, 0, 5, 3, 0, -1}
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz_rev7[] = {
+ {0, 0, 0, 0, 0, 100},
+ {0, 0, 0, 0, 0, 50},
+ {0, 0, 0, 0, 0, -1},
+ {0, 0, 0, 3, 0, -1},
+ {0, 0, 3, 3, 0, -1},
+ {0, 0, 5, 3, 0, -1}
};
-struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz_rev7[] = {
-{0, 0, 0, 0, 0, 10},
-{0, 0, 0, 1, 0, 10},
-{0, 0, 1, 2, 0, 10},
-{0, 0, 1, 3, 0, 10},
-{0, 0, 4, 3, 0, 10},
-{0, 0, 6, 3, 0, 10}
+static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz_rev7[] = {
+ {0, 0, 0, 0, 0, 10},
+ {0, 0, 0, 1, 0, 10},
+ {0, 0, 1, 2, 0, 10},
+ {0, 0, 1, 3, 0, 10},
+ {0, 0, 4, 3, 0, 10},
+ {0, 0, 6, 3, 0, 10}
};
-#define NPHY_RXCAL_TONEAMP 181
-#define NPHY_RXCAL_TONEFREQ_40MHz 4000
-#define NPHY_RXCAL_TONEFREQ_20MHz 2000
-
enum {
NPHY_RXCAL_GAIN_INIT = 0,
NPHY_RXCAL_GAIN_UP,
@@ -230,17 +263,11 @@ enum {
#define wlc_phy_get_papd_nphy(pi) \
(read_phy_reg((pi), 0x1e7) & \
- ((0x1 << 15) | \
- (0x1 << 14) | \
- (0x1 << 13)))
+ ((0x1 << 15) | \
+ (0x1 << 14) | \
+ (0x1 << 13)))
-#define TXFILT_SHAPING_OFDM20 0
-#define TXFILT_SHAPING_OFDM40 1
-#define TXFILT_SHAPING_CCK 2
-#define TXFILT_DEFAULT_OFDM20 3
-#define TXFILT_DEFAULT_OFDM40 4
-
-u16 NPHY_IPA_REV4_txdigi_filtcoeffs[][NPHY_NUM_DIG_FILT_COEFFS] = {
+static const u16 NPHY_IPA_REV4_txdigi_filtcoeffs[][NPHY_NUM_DIG_FILT_COEFFS] = {
{-377, 137, -407, 208, -1527, 956, 93, 186, 93,
230, -44, 230, 201, -191, 201},
{-77, 20, -98, 49, -93, 60, 56, 111, 56, 26, -5,
@@ -416,7 +443,7 @@ struct nphy_sfo_cfg {
u16 PHY_BW6;
};
-static struct chan_info_nphy_2055 chan_info_nphy_2055[] = {
+static const struct chan_info_nphy_2055 chan_info_nphy_2055[] = {
{
184, 4920, 3280, 0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F,
@@ -915,7 +942,7 @@ static struct chan_info_nphy_2055 chan_info_nphy_2055[] = {
0x01, 0x80, 0x3E6, 0x3E2, 0x3DE, 0x41B, 0x41F, 0x424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev3_2056[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev3_2056[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f,
@@ -1538,7 +1565,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev3_2056[] = {
0x0f, 0x00, 0x0d, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev4_2056_A1[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev4_2056_A1[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f,
@@ -2161,7 +2188,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev4_2056_A1[] = {
0x0f, 0x00, 0x0e, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev5_2056v5[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev5_2056v5[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
@@ -2784,7 +2811,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev5_2056v5[] = {
0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v6[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v6[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
@@ -3407,7 +3434,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v6[] = {
0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev5n6_2056v7[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev5n6_2056v7[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70,
@@ -4030,7 +4057,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev5n6_2056v7[] = {
0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v8[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v8[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
@@ -4653,7 +4680,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v8[] = {
0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v11[] = {
+static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v11[] = {
{
184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x02, 0x0c, 0x01,
0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77,
@@ -5276,7 +5303,7 @@ static struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v11[] = {
0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio2057 chan_info_nphyrev7_2057_rev4[] = {
+static const struct chan_info_nphy_radio2057 chan_info_nphyrev7_2057_rev4[] = {
{
184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f,
0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00,
@@ -6139,7 +6166,8 @@ static struct chan_info_nphy_radio2057 chan_info_nphyrev7_2057_rev4[] = {
0x0424}
};
-static struct chan_info_nphy_radio2057_rev5 chan_info_nphyrev8_2057_rev5[] = {
+static const struct chan_info_nphy_radio2057_rev5
+chan_info_nphyrev8_2057_rev5[] = {
{
1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d,
0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1,
@@ -6198,7 +6226,8 @@ static struct chan_info_nphy_radio2057_rev5 chan_info_nphyrev8_2057_rev5[] = {
0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio2057_rev5 chan_info_nphyrev9_2057_rev5v1[] = {
+static const struct chan_info_nphy_radio2057_rev5
+chan_info_nphyrev9_2057_rev5v1[] = {
{
1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d,
0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1,
@@ -6257,7 +6286,7 @@ static struct chan_info_nphy_radio2057_rev5 chan_info_nphyrev9_2057_rev5v1[] = {
0x041b, 0x041f, 0x0424}
};
-static struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev7[] = {
+static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev7[] = {
{
184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f,
0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
@@ -6998,7 +7027,7 @@ static struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev7[] = {
0x0424}
};
-static struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev8[] = {
+static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev8[] = {
{
186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f,
0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00,
@@ -7733,7 +7762,7 @@ static struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev8[] = {
0x0424}
};
-struct radio_regs regs_2055[] = {
+static struct radio_regs regs_2055[] = {
{0x02, 0x80, 0x80, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0x27, 0x27, 0, 0},
@@ -7962,7 +7991,7 @@ struct radio_regs regs_2055[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_SYN_2056[] = {
+static struct radio_regs regs_SYN_2056[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -8147,7 +8176,7 @@ struct radio_regs regs_SYN_2056[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_TX_2056[] = {
+static struct radio_regs regs_TX_2056[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -8296,7 +8325,7 @@ struct radio_regs regs_TX_2056[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_RX_2056[] = {
+static struct radio_regs regs_RX_2056[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -8447,7 +8476,7 @@ struct radio_regs regs_RX_2056[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_SYN_2056_A1[] = {
+static struct radio_regs regs_SYN_2056_A1[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -8632,7 +8661,7 @@ struct radio_regs regs_SYN_2056_A1[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_TX_2056_A1[] = {
+static struct radio_regs regs_TX_2056_A1[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -8781,7 +8810,7 @@ struct radio_regs regs_TX_2056_A1[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_RX_2056_A1[] = {
+static struct radio_regs regs_RX_2056_A1[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -8932,7 +8961,7 @@ struct radio_regs regs_RX_2056_A1[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_SYN_2056_rev5[] = {
+static struct radio_regs regs_SYN_2056_rev5[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -9117,7 +9146,7 @@ struct radio_regs regs_SYN_2056_rev5[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_TX_2056_rev5[] = {
+static struct radio_regs regs_TX_2056_rev5[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -9274,7 +9303,7 @@ struct radio_regs regs_TX_2056_rev5[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_RX_2056_rev5[] = {
+static struct radio_regs regs_RX_2056_rev5[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -9425,7 +9454,7 @@ struct radio_regs regs_RX_2056_rev5[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_SYN_2056_rev6[] = {
+static struct radio_regs regs_SYN_2056_rev6[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -9610,7 +9639,7 @@ struct radio_regs regs_SYN_2056_rev6[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_TX_2056_rev6[] = {
+static struct radio_regs regs_TX_2056_rev6[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -9767,7 +9796,7 @@ struct radio_regs regs_TX_2056_rev6[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_RX_2056_rev6[] = {
+static struct radio_regs regs_RX_2056_rev6[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -9918,7 +9947,7 @@ struct radio_regs regs_RX_2056_rev6[] = {
{0xFFFF, 0, 0, 0, 0}
};
-struct radio_regs regs_SYN_2056_rev7[] = {
+static struct radio_regs regs_SYN_2056_rev7[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -10103,7 +10132,7 @@ struct radio_regs regs_SYN_2056_rev7[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_TX_2056_rev7[] = {
+static struct radio_regs regs_TX_2056_rev7[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -10260,7 +10289,7 @@ struct radio_regs regs_TX_2056_rev7[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_RX_2056_rev7[] = {
+static struct radio_regs regs_RX_2056_rev7[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -10411,7 +10440,7 @@ struct radio_regs regs_RX_2056_rev7[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_SYN_2056_rev8[] = {
+static struct radio_regs regs_SYN_2056_rev8[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -10596,7 +10625,7 @@ struct radio_regs regs_SYN_2056_rev8[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_TX_2056_rev8[] = {
+static struct radio_regs regs_TX_2056_rev8[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -10753,7 +10782,7 @@ struct radio_regs regs_TX_2056_rev8[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_RX_2056_rev8[] = {
+static struct radio_regs regs_RX_2056_rev8[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -10904,7 +10933,7 @@ struct radio_regs regs_RX_2056_rev8[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_SYN_2056_rev11[] = {
+static const struct radio_regs regs_SYN_2056_rev11[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -11089,7 +11118,7 @@ struct radio_regs regs_SYN_2056_rev11[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_TX_2056_rev11[] = {
+static const struct radio_regs regs_TX_2056_rev11[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -11246,7 +11275,7 @@ struct radio_regs regs_TX_2056_rev11[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_regs regs_RX_2056_rev11[] = {
+static const struct radio_regs regs_RX_2056_rev11[] = {
{0x02, 0, 0, 0, 0},
{0x03, 0, 0, 0, 0},
{0x04, 0, 0, 0, 0},
@@ -11397,7 +11426,7 @@ struct radio_regs regs_RX_2056_rev11[] = {
{0xFFFF, 0, 0, 0, 0},
};
-struct radio_20xx_regs regs_2057_rev4[] = {
+static struct radio_20xx_regs regs_2057_rev4[] = {
{0x00, 0x84, 0},
{0x01, 0, 0},
{0x02, 0x60, 0},
@@ -11787,7 +11816,7 @@ struct radio_20xx_regs regs_2057_rev4[] = {
{0xFFFF, 0, 0},
};
-struct radio_20xx_regs regs_2057_rev5[] = {
+static struct radio_20xx_regs regs_2057_rev5[] = {
{0x00, 0, 1},
{0x01, 0x57, 1},
{0x02, 0x20, 1},
@@ -12119,7 +12148,7 @@ struct radio_20xx_regs regs_2057_rev5[] = {
{0xFFFF, 0, 0}
};
-struct radio_20xx_regs regs_2057_rev5v1[] = {
+static struct radio_20xx_regs regs_2057_rev5v1[] = {
{0x00, 0x15, 1},
{0x01, 0x57, 1},
{0x02, 0x20, 1},
@@ -12451,7 +12480,7 @@ struct radio_20xx_regs regs_2057_rev5v1[] = {
{0xFFFF, 0, 0}
};
-struct radio_20xx_regs regs_2057_rev7[] = {
+static struct radio_20xx_regs regs_2057_rev7[] = {
{0x00, 0, 1},
{0x01, 0x57, 1},
{0x02, 0x20, 1},
@@ -12867,7 +12896,7 @@ struct radio_20xx_regs regs_2057_rev7[] = {
{0xFFFF, 0, 0}
};
-struct radio_20xx_regs regs_2057_rev8[] = {
+static struct radio_20xx_regs regs_2057_rev8[] = {
{0x00, 0x8, 1},
{0x01, 0x57, 1},
{0x02, 0x20, 1},
@@ -13290,27 +13319,27 @@ static s32 nphy_lnagain_est1[] = { -224, 23242 };
static const u16 tbl_iqcal_gainparams_nphy[2][NPHY_IQCAL_NUMGAINS][8] = {
{
- {0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69},
- {0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69},
- {0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68},
- {0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67},
- {0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66},
- {0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65},
- {0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65},
- {0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65},
- {0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65}
- },
- {
- {0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79},
- {0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79},
- {0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79},
- {0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78},
- {0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78},
- {0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78},
- {0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78},
- {0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78},
- {0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78}
- }
+ {0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69},
+ {0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69},
+ {0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68},
+ {0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67},
+ {0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66},
+ {0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65},
+ {0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65},
+ {0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65},
+ {0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65}
+ },
+ {
+ {0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79},
+ {0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79},
+ {0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79},
+ {0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78},
+ {0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78},
+ {0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78},
+ {0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78},
+ {0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78},
+ {0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78}
+ }
};
static const u32 nphy_tpc_txgain[] = {
@@ -14081,118 +14110,11 @@ static u32 nphy_tpc_5GHz_txgain_HiPwrEPA[] = {
static u8 ant_sw_ctrl_tbl_rev8_2o3[] = { 0x14, 0x18 };
static u8 ant_sw_ctrl_tbl_rev8[] = { 0x4, 0x8, 0x4, 0x8, 0x11, 0x12 };
static u8 ant_sw_ctrl_tbl_rev8_2057v7_core0[] = {
- 0x09, 0x0a, 0x15, 0x16, 0x09, 0x0a };
+ 0x09, 0x0a, 0x15, 0x16, 0x09, 0x0a
+};
static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = {
- 0x09, 0x0a, 0x09, 0x0a, 0x15, 0x16 };
-
-static bool wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
- struct chan_info_nphy_radio2057 **t0,
- struct chan_info_nphy_radio205x **t1,
- struct chan_info_nphy_radio2057_rev5 **t2,
- struct chan_info_nphy_2055 **t3);
-static void wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, chanspec_t chans,
- const struct nphy_sfo_cfg *c);
-
-static void wlc_phy_adjust_rx_analpfbw_nphy(struct brcms_phy *pi,
- u16 reduction_factr);
-static void wlc_phy_adjust_min_noisevar_nphy(struct brcms_phy *pi,
- int ntones, int *, u32 *buf);
-static void wlc_phy_adjust_crsminpwr_nphy(struct brcms_phy *pi, u8 minpwr);
-static void wlc_phy_txlpfbw_nphy(struct brcms_phy *pi);
-static void wlc_phy_spurwar_nphy(struct brcms_phy *pi);
-
-static void wlc_phy_radio_preinit_2055(struct brcms_phy *pi);
-static void wlc_phy_radio_init_2055(struct brcms_phy *pi);
-static void wlc_phy_radio_postinit_2055(struct brcms_phy *pi);
-static void wlc_phy_radio_preinit_205x(struct brcms_phy *pi);
-static void wlc_phy_radio_init_2056(struct brcms_phy *pi);
-static void wlc_phy_radio_postinit_2056(struct brcms_phy *pi);
-static void wlc_phy_radio_init_2057(struct brcms_phy *pi);
-static void wlc_phy_radio_postinit_2057(struct brcms_phy *pi);
-static void wlc_phy_workarounds_nphy(struct brcms_phy *pi);
-static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi);
-static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi);
-static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi);
-static void wlc_phy_adjust_lnagaintbl_nphy(struct brcms_phy *pi);
-
-static void wlc_phy_restore_rssical_nphy(struct brcms_phy *pi);
-static void wlc_phy_reapply_txcal_coeffs_nphy(struct brcms_phy *pi);
-static void wlc_phy_tx_iq_war_nphy(struct brcms_phy *pi);
-static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
- struct nphy_txgains tg, u8 type, bool d);
-static void wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rxcore,
- u16 *rg, u8 type);
-static void wlc_phy_update_mimoconfig_nphy(struct brcms_phy *pi, s32 preamble);
-static void wlc_phy_savecal_nphy(struct brcms_phy *pi);
-static void wlc_phy_restorecal_nphy(struct brcms_phy *pi);
-static void wlc_phy_resetcca_nphy(struct brcms_phy *pi);
-
-static void wlc_phy_txpwrctrl_config_nphy(struct brcms_phy *pi);
-static void wlc_phy_internal_cal_txgain_nphy(struct brcms_phy *pi);
-static void wlc_phy_precal_txgain_nphy(struct brcms_phy *pi);
-static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core);
-
-static void wlc_phy_extpa_set_tx_digi_filts_nphy(struct brcms_phy *pi);
-static void wlc_phy_ipa_set_tx_digi_filts_nphy(struct brcms_phy *pi);
-static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi);
-static u16 wlc_phy_ipa_get_bbmult_nphy(struct brcms_phy *pi);
-static void wlc_phy_ipa_set_bbmult_nphy(struct brcms_phy *pi, u8 m0, u8 m1);
-static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi);
-
-static void wlc_phy_a1_nphy(struct brcms_phy *pi, u8 core, u32 winsz, u32,
- u32 e);
-static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core);
-static void wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *,
- enum phy_cal_mode, u8);
-static void wlc_phy_papd_cal_cleanup_nphy(struct brcms_phy *pi,
- struct nphy_papd_restore_state *state);
-static void wlc_phy_papd_cal_setup_nphy(struct brcms_phy *pi,
- struct nphy_papd_restore_state *state, u8);
-
-static void wlc_phy_clip_det_nphy(struct brcms_phy *pi, u8 write, u16 *vals);
-
-static void wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *evts,
- u8 *dlys, u8 len);
-
-static u16 wlc_phy_read_lpf_bw_ctl_nphy(struct brcms_phy *pi, u16 offset);
-
-static void
-wlc_phy_rfctrl_override_nphy_rev7(struct brcms_phy *pi, u16 field, u16 value,
- u8 core_mask, u8 off,
- u8 override_id);
-
-static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type);
-static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi);
-
-static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi);
-static void wlc_phy_txpwr_nphy_srom_convert(u8 *srom_max,
- u16 *pwr_offset,
- u8 tmp_max_pwr, u8 rate_start,
- u8 rate_end);
-
-static void wlc_phy_txpwr_limit_to_tbl_nphy(struct brcms_phy *pi);
-static void wlc_phy_txpwrctrl_coeff_setup_nphy(struct brcms_phy *pi);
-static void wlc_phy_txpwrctrl_idle_tssi_nphy(struct brcms_phy *pi);
-static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi);
-
-static bool wlc_phy_txpwr_ison_nphy(struct brcms_phy *pi);
-static u8 wlc_phy_txpwr_idx_cur_get_nphy(struct brcms_phy *pi, u8 core);
-static void wlc_phy_txpwr_idx_cur_set_nphy(struct brcms_phy *pi, u8 idx0,
- u8 idx1);
-static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal);
-
-static u16 wlc_phy_radio205x_rcal(struct brcms_phy *pi);
-
-static u16 wlc_phy_radio2057_rccal(struct brcms_phy *pi);
-
-static u16 wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz,
- u16 max_val,
- u8 dac_test_mode);
-static void wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, cs32 *tone_buf,
- u16 num_samps);
-static void wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 n, u16 lps,
- u16 wait, u8 iq, u8 dac_test_mode,
- bool modify_bbmult);
+ 0x09, 0x0a, 0x09, 0x0a, 0x15, 0x16
+};
bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih)
{
@@ -14209,9 +14131,8 @@ bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih)
phybist4 = read_phy_reg(pi, 0x156);
if ((phybist0 == 0) && (phybist1 == 0x4000) && (phybist2 == 0x1fe0) &&
- (phybist3 == 0) && (phybist4 == 0)) {
+ (phybist3 == 0) && (phybist4 == 0))
return true;
- }
return false;
}
@@ -14230,18 +14151,7 @@ static void wlc_phy_bphy_init_nphy(struct brcms_phy *pi)
val -= 0x0202;
}
- if (NORADIO_ENAB(pi->pubpi)) {
-
- write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_PHYCRSTH, 0x3206);
-
- write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_RSSI_TRESH, 0x281e);
-
- or_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_LNA_GAIN_RANGE, 0x1a);
-
- } else {
-
- write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_STEP, 0x668);
- }
+ write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_STEP, 0x668);
}
void
@@ -14307,7 +14217,8 @@ static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi)
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
antswctrllut = CHSPEC_IS2G(pi->radio_chanspec) ?
- pi->srom_fem2g.antswctrllut : pi->srom_fem5g.antswctrllut;
+ pi->srom_fem2g.antswctrllut : pi->srom_fem5g.
+ antswctrllut;
switch (antswctrllut) {
case 0:
@@ -14316,20 +14227,20 @@ static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi)
case 1:
- if (pi->aa2g == 7) {
+ if (pi->aa2g == 7)
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x21, 8,
+ &ant_sw_ctrl_tbl_rev8_2o3[0]);
+ else
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x21, 8,
+ &ant_sw_ctrl_tbl_rev8
+ [0]);
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x21, 8,
- &ant_sw_ctrl_tbl_rev8_2o3
- [0]);
- } else {
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x21, 8,
- &ant_sw_ctrl_tbl_rev8
- [0]);
- }
wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
2, 0x25, 8,
&ant_sw_ctrl_tbl_rev8[2]);
@@ -14340,31 +14251,31 @@ static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi)
case 2:
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x1, 8,
- &ant_sw_ctrl_tbl_rev8_2057v7_core0
- [0]);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x5, 8,
- &ant_sw_ctrl_tbl_rev8_2057v7_core0
- [2]);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x9, 8,
- &ant_sw_ctrl_tbl_rev8_2057v7_core0
- [4]);
-
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x21, 8,
- &ant_sw_ctrl_tbl_rev8_2057v7_core1
- [0]);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x25, 8,
- &ant_sw_ctrl_tbl_rev8_2057v7_core1
- [2]);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT,
- 2, 0x29, 8,
- &ant_sw_ctrl_tbl_rev8_2057v7_core1
- [4]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x1, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core0[0]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x5, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core0[2]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x9, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core0[4]);
+
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x21, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core1[0]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x25, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core1[2]);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_ANTSWCTRLLUT,
+ 2, 0x29, 8,
+ &ant_sw_ctrl_tbl_rev8_2057v7_core1[4]);
break;
default:
@@ -14375,45 +14286,49 @@ static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi)
for (idx = 0; idx < mimophytbl_info_sz_rev3_volatile; idx++) {
if (idx == ANT_SWCTRL_TBL_REV3_IDX) {
- antswctrllut = CHSPEC_IS2G(pi->radio_chanspec) ?
- pi->srom_fem2g.antswctrllut : pi->
- srom_fem5g.antswctrllut;
+ antswctrllut =
+ CHSPEC_IS2G(pi->radio_chanspec) ?
+ pi->srom_fem2g.antswctrllut :
+ pi->srom_fem5g.antswctrllut;
switch (antswctrllut) {
case 0:
- wlc_phy_write_table_nphy(pi,
- &mimophytbl_info_rev3_volatile
- [idx]);
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile
+ [idx]);
break;
case 1:
- wlc_phy_write_table_nphy(pi,
- &mimophytbl_info_rev3_volatile1
- [idx]);
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile1
+ [idx]);
break;
case 2:
- wlc_phy_write_table_nphy(pi,
- &mimophytbl_info_rev3_volatile2
- [idx]);
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile2
+ [idx]);
break;
case 3:
- wlc_phy_write_table_nphy(pi,
- &mimophytbl_info_rev3_volatile3
- [idx]);
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile3
+ [idx]);
break;
default:
break;
}
} else {
- wlc_phy_write_table_nphy(pi,
- &mimophytbl_info_rev3_volatile
- [idx]);
+ wlc_phy_write_table_nphy(
+ pi,
+ &mimophytbl_info_rev3_volatile[idx]);
}
}
} else {
- for (idx = 0; idx < mimophytbl_info_sz_rev0_volatile; idx++) {
+ for (idx = 0; idx < mimophytbl_info_sz_rev0_volatile; idx++)
wlc_phy_write_table_nphy(pi,
&mimophytbl_info_rev0_volatile
[idx]);
- }
}
}
@@ -14440,32 +14355,414 @@ void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs)
wlc_phy_write_txmacreg_nphy(pi, holdoff, delay);
- if (pi && pi->sh && (pi->sh->_rifs_phy != rifs)) {
+ if (pi && pi->sh && (pi->sh->_rifs_phy != rifs))
pi->sh->_rifs_phy = rifs;
+}
+
+static void wlc_phy_txpwrctrl_config_nphy(struct brcms_phy *pi)
+{
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ pi->nphy_txpwrctrl = PHY_TPC_HW_ON;
+ pi->phy_5g_pwrgain = true;
+ return;
+ }
+
+ pi->nphy_txpwrctrl = PHY_TPC_HW_OFF;
+ pi->phy_5g_pwrgain = false;
+
+ if ((pi->sh->boardflags2 & BFL2_TXPWRCTRL_EN) &&
+ NREV_GE(pi->pubpi.phy_rev, 2) && (pi->sh->sromrev >= 4))
+ pi->nphy_txpwrctrl = PHY_TPC_HW_ON;
+ else if ((pi->sh->sromrev >= 4)
+ && (pi->sh->boardflags2 & BFL2_5G_PWRGAIN))
+ pi->phy_5g_pwrgain = true;
+}
+
+static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
+{
+ u16 bw40po, cddpo, stbcpo, bwduppo;
+ uint band_num;
+ struct phy_shim_info *shim = pi->sh->physhim;
+
+ if (pi->sh->sromrev >= 9)
+ return;
+
+ bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO);
+ pi->bw402gpo = bw40po & 0xf;
+ pi->bw405gpo = (bw40po & 0xf0) >> 4;
+ pi->bw405glpo = (bw40po & 0xf00) >> 8;
+ pi->bw405ghpo = (bw40po & 0xf000) >> 12;
+
+ cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO);
+ pi->cdd2gpo = cddpo & 0xf;
+ pi->cdd5gpo = (cddpo & 0xf0) >> 4;
+ pi->cdd5glpo = (cddpo & 0xf00) >> 8;
+ pi->cdd5ghpo = (cddpo & 0xf000) >> 12;
+
+ stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO);
+ pi->stbc2gpo = stbcpo & 0xf;
+ pi->stbc5gpo = (stbcpo & 0xf0) >> 4;
+ pi->stbc5glpo = (stbcpo & 0xf00) >> 8;
+ pi->stbc5ghpo = (stbcpo & 0xf000) >> 12;
+
+ bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO);
+ pi->bwdup2gpo = bwduppo & 0xf;
+ pi->bwdup5gpo = (bwduppo & 0xf0) >> 4;
+ pi->bwdup5glpo = (bwduppo & 0xf00) >> 8;
+ pi->bwdup5ghpo = (bwduppo & 0xf000) >> 12;
+
+ for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP);
+ band_num++) {
+ switch (band_num) {
+ case 0:
+
+ pi->nphy_txpid2g[PHY_CORE_0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID2GA0);
+ pi->nphy_txpid2g[PHY_CORE_1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID2GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP2GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP2GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW0A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW0A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW1A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW1A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW2A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA2GW2A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1);
+
+ pi->cck2gpo = (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_CCK2GPO);
+
+ pi->ofdm2gpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM2GPO);
+
+ pi->mcs2gpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO0);
+ pi->mcs2gpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO1);
+ pi->mcs2gpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO2);
+ pi->mcs2gpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO3);
+ pi->mcs2gpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO4);
+ pi->mcs2gpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO5);
+ pi->mcs2gpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO6);
+ pi->mcs2gpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS2GPO7);
+ break;
+ case 1:
+
+ pi->nphy_txpid5g[PHY_CORE_0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GA0);
+ pi->nphy_txpid5g[PHY_CORE_1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GA1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW0A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW0A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW1A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW1A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW2A0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GW2A1);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm =
+ (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1);
+
+ pi->ofdm5gpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM5GPO);
+
+ pi->mcs5gpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO0);
+ pi->mcs5gpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO1);
+ pi->mcs5gpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO2);
+ pi->mcs5gpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO3);
+ pi->mcs5gpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO4);
+ pi->mcs5gpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO5);
+ pi->mcs5gpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO6);
+ pi->mcs5gpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GPO7);
+ break;
+ case 2:
+
+ pi->nphy_txpid5gl[0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GLA0);
+ pi->nphy_txpid5gl[1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GLA1);
+ pi->nphy_pwrctrl_info[0].max_pwr_5gl =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GLA0);
+ pi->nphy_pwrctrl_info[1].max_pwr_5gl =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GLA1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW0A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW0A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW1A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW1A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW2A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GLW2A1);
+ pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0;
+ pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0;
+
+ pi->ofdm5glpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM5GLPO);
+
+ pi->mcs5glpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO0);
+ pi->mcs5glpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO1);
+ pi->mcs5glpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO2);
+ pi->mcs5glpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO3);
+ pi->mcs5glpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO4);
+ pi->mcs5glpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO5);
+ pi->mcs5glpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO6);
+ pi->mcs5glpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GLPO7);
+ break;
+ case 3:
+
+ pi->nphy_txpid5gh[0] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GHA0);
+ pi->nphy_txpid5gh[1] =
+ (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TXPID5GHA1);
+ pi->nphy_pwrctrl_info[0].max_pwr_5gh =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GHA0);
+ pi->nphy_pwrctrl_info[1].max_pwr_5gh =
+ (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_MAXP5GHA1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW0A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW0A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW1A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW1A1);
+ pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW2A0);
+ pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 =
+ (s16) wlapi_getintvar(shim,
+ BRCMS_SROM_PA5GHW2A1);
+ pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0;
+ pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0;
+
+ pi->ofdm5ghpo =
+ (u32) wlapi_getintvar(shim,
+ BRCMS_SROM_OFDM5GHPO);
+
+ pi->mcs5ghpo[0] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO0);
+ pi->mcs5ghpo[1] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO1);
+ pi->mcs5ghpo[2] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO2);
+ pi->mcs5ghpo[3] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO3);
+ pi->mcs5ghpo[4] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO4);
+ pi->mcs5ghpo[5] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO5);
+ pi->mcs5ghpo[6] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO6);
+ pi->mcs5ghpo[7] =
+ (u16) wlapi_getintvar(shim,
+ BRCMS_SROM_MCS5GHPO7);
+ break;
+ }
}
+
+ wlc_phy_txpwr_apply_nphy(pi);
+}
+
+static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
+{
+ struct phy_shim_info *shim = pi->sh->physhim;
+
+ pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH);
+ pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G);
+ pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G);
+
+ pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TSSIPOS2G);
+ pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_EXTPAGAIN2G);
+ pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_PDETRANGE2G);
+ pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
+ pi->srom_fem2g.antswctrllut =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
+
+ pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_TSSIPOS5G);
+ pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_EXTPAGAIN5G);
+ pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim,
+ BRCMS_SROM_PDETRANGE5G);
+ pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G);
+ if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G))
+ pi->srom_fem5g.antswctrllut =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G);
+ else
+ pi->srom_fem5g.antswctrllut =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
+
+ wlc_phy_txpower_ipa_upd(pi);
+
+ pi->phy_txcore_disable_temp =
+ (s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH);
+ if (pi->phy_txcore_disable_temp == 0)
+ pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
+
+ pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim,
+ BRCMS_SROM_TEMPOFFSET);
+ if (pi->phy_tempsense_offset != 0) {
+ if (pi->phy_tempsense_offset >
+ (NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET))
+ pi->phy_tempsense_offset = NPHY_SROM_MAXTEMPOFFSET;
+ else if (pi->phy_tempsense_offset < (NPHY_SROM_TEMPSHIFT +
+ NPHY_SROM_MINTEMPOFFSET))
+ pi->phy_tempsense_offset = NPHY_SROM_MINTEMPOFFSET;
+ else
+ pi->phy_tempsense_offset -= NPHY_SROM_TEMPSHIFT;
+ }
+
+ pi->phy_txcore_enable_temp =
+ pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP;
+
+ pi->phycal_tempdelta =
+ (u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA);
+ if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA)
+ pi->phycal_tempdelta = 0;
+
+ wlc_phy_txpwr_srom_read_ppr_nphy(pi);
+
+ return true;
}
bool wlc_phy_attach_nphy(struct brcms_phy *pi)
{
uint i;
- if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 6)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 6))
pi->phyhang_avoid = true;
- }
if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
-
pi->nphy_gband_spurwar_en = true;
-
- if (pi->sh->boardflags2 & BFL2_SPUR_WAR) {
+ if (pi->sh->boardflags2 & BFL2_SPUR_WAR)
pi->nphy_aband_spurwar_en = true;
- }
}
if (NREV_GE(pi->pubpi.phy_rev, 6) && NREV_LT(pi->pubpi.phy_rev, 7)) {
-
- if (pi->sh->boardflags2 & BFL2_2G_SPUR_WAR) {
+ if (pi->sh->boardflags2 & BFL2_2G_SPUR_WAR)
pi->nphy_gband_spurwar2_en = true;
- }
}
pi->n_preamble_override = AUTO;
@@ -14485,9 +14782,8 @@ bool wlc_phy_attach_nphy(struct brcms_phy *pi)
pi->nphy_elna_gain_config = false;
pi->radio_is_on = false;
- for (i = 0; i < pi->pubpi.phy_corenum; i++) {
+ for (i = 0; i < pi->pubpi.phy_corenum; i++)
pi->nphy_txpwrindex[i].index = AUTO;
- }
wlc_phy_txpwrctrl_config_nphy(pi);
if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON)
@@ -14504,751 +14800,1405 @@ bool wlc_phy_attach_nphy(struct brcms_phy *pi)
return true;
}
-static void wlc_phy_txpwrctrl_config_nphy(struct brcms_phy *pi)
+static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn)
{
+ s32 rfpwr_offset = 0;
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- pi->nphy_txpwrctrl = PHY_TPC_HW_ON;
- pi->phy_5g_pwrgain = true;
- return;
- }
-
- pi->nphy_txpwrctrl = PHY_TPC_HW_OFF;
- pi->phy_5g_pwrgain = false;
-
- if ((pi->sh->boardflags2 & BFL2_TXPWRCTRL_EN) &&
- NREV_GE(pi->pubpi.phy_rev, 2) && (pi->sh->sromrev >= 4))
- pi->nphy_txpwrctrl = PHY_TPC_HW_ON;
- else if ((pi->sh->sromrev >= 4)
- && (pi->sh->boardflags2 & BFL2_5G_PWRGAIN))
- pi->phy_5g_pwrgain = true;
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ rfpwr_offset = (s16)
+ nphy_papd_padgain_dlt_2g_2057rev3n4
+ [pad_gn];
+ else if (pi->pubpi.radiorev == 5)
+ rfpwr_offset = (s16)
+ nphy_papd_padgain_dlt_2g_2057rev5
+ [pad_gn];
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev ==
+ 8))
+ rfpwr_offset = (s16)
+ nphy_papd_padgain_dlt_2g_2057rev7
+ [pad_gn];
+ } else {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ rfpwr_offset = (s16)
+ nphy_papd_pgagain_dlt_5g_2057
+ [pga_gn];
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev ==
+ 8))
+ rfpwr_offset = (s16)
+ nphy_papd_pgagain_dlt_5g_2057rev7
+ [pga_gn];
+ }
+ return rfpwr_offset;
}
-void wlc_phy_init_nphy(struct brcms_phy *pi)
+static void wlc_phy_update_mimoconfig_nphy(struct brcms_phy *pi, s32 preamble)
{
+ bool gf_preamble = false;
u16 val;
- u16 clip1_ths[2];
- struct nphy_txgains target_gain;
- u8 tx_pwr_ctrl_state;
- bool do_nphy_cal = false;
- uint core;
- uint origidx, intr_val;
- d11regs_t *regs;
- u32 d11_clk_ctl_st;
- core = 0;
-
- if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) {
- pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
- }
+ if (preamble == BRCMS_N_PREAMBLE_GF)
+ gf_preamble = true;
- if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) &&
- ((pi->sh->chippkg == BCM4717_PKG_ID) ||
- (pi->sh->chippkg == BCM4718_PKG_ID))) {
- if ((pi->sh->boardflags & BFL_EXTLNA) &&
- (CHSPEC_IS2G(pi->radio_chanspec))) {
- ai_corereg(pi->sh->sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol), 0x40,
- 0x40);
- }
- }
+ val = read_phy_reg(pi, 0xed);
- if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) &&
- CHSPEC_IS40(pi->radio_chanspec)) {
+ val |= RX_GF_MM_AUTO;
+ val &= ~RX_GF_OR_MM;
+ if (gf_preamble)
+ val |= RX_GF_OR_MM;
- regs = (d11regs_t *) ai_switch_core(pi->sh->sih, D11_CORE_ID,
- &origidx, &intr_val);
- d11_clk_ctl_st = R_REG(&regs->clk_ctl_st);
- AND_REG(&regs->clk_ctl_st,
- ~(CCS_FORCEHT | CCS_HTAREQ));
+ write_phy_reg(pi, 0xed, val);
+}
- W_REG(&regs->clk_ctl_st, d11_clk_ctl_st);
+static void wlc_phy_ipa_set_tx_digi_filts_nphy(struct brcms_phy *pi)
+{
+ int j, type;
+ u16 addr_offset[] = { 0x186, 0x195, 0x2c5};
- ai_restore_core(pi->sh->sih, origidx, intr_val);
+ for (type = 0; type < 3; type++) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr_offset[type] + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]);
}
- pi->use_int_tx_iqlo_cal_nphy =
- (PHY_IPA(pi) ||
- (NREV_GE(pi->pubpi.phy_rev, 7) ||
- (NREV_GE(pi->pubpi.phy_rev, 5)
- && pi->sh->boardflags2 & BFL2_INTERNDET_TXIQCAL)));
-
- pi->internal_tx_iqlo_cal_tapoff_intpa_nphy = false;
-
- pi->nphy_deaf_count = 0;
-
- wlc_phy_tbl_init_nphy(pi);
-
- pi->nphy_crsminpwr_adjusted = false;
- pi->nphy_noisevars_adjusted = false;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- write_phy_reg(pi, 0xe7, 0);
- write_phy_reg(pi, 0xec, 0);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- write_phy_reg(pi, 0x342, 0);
- write_phy_reg(pi, 0x343, 0);
- write_phy_reg(pi, 0x346, 0);
- write_phy_reg(pi, 0x347, 0);
- }
- write_phy_reg(pi, 0xe5, 0);
- write_phy_reg(pi, 0xe6, 0);
+ if (pi->bw == WL_CHANSPEC_BW_40) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x186 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]);
} else {
- write_phy_reg(pi, 0xec, 0);
- }
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x186 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[5][j]);
+ }
- write_phy_reg(pi, 0x91, 0);
- write_phy_reg(pi, 0x92, 0);
- if (NREV_LT(pi->pubpi.phy_rev, 6)) {
- write_phy_reg(pi, 0x93, 0);
- write_phy_reg(pi, 0x94, 0);
+ if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x2c5 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[6][j]);
+ }
}
+}
- and_phy_reg(pi, 0xa1, ~3);
+static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi)
+{
+ int j;
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- write_phy_reg(pi, 0x8f, 0);
- write_phy_reg(pi, 0xa5, 0);
+ if (pi->bw == WL_CHANSPEC_BW_40) {
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x195 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[4][j]);
} else {
- write_phy_reg(pi, 0xa5, 0);
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, 0x186 + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]);
}
+}
- if (NREV_IS(pi->pubpi.phy_rev, 2))
- mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b);
- else if (NREV_LT(pi->pubpi.phy_rev, 2))
- mod_phy_reg(pi, 0xdc, 0x00ff, 0x40);
-
- write_phy_reg(pi, 0x203, 32);
- write_phy_reg(pi, 0x201, 32);
-
- if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD)
- write_phy_reg(pi, 0x20d, 160);
- else
- write_phy_reg(pi, 0x20d, 184);
-
- write_phy_reg(pi, 0x13a, 200);
-
- write_phy_reg(pi, 0x70, 80);
-
- write_phy_reg(pi, 0x1ff, 48);
+static void
+wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys,
+ u8 len)
+{
+ u32 t1_offset, t2_offset;
+ u8 ctr;
+ u8 end_event =
+ NREV_GE(pi->pubpi.phy_rev,
+ 3) ? NPHY_REV3_RFSEQ_CMD_END : NPHY_RFSEQ_CMD_END;
+ u8 end_dly = 1;
- if (NREV_LT(pi->pubpi.phy_rev, 8)) {
- wlc_phy_update_mimoconfig_nphy(pi, pi->n_preamble_override);
- }
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
- wlc_phy_stf_chain_upd_nphy(pi);
+ t1_offset = cmd << 4;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t1_offset, 8,
+ events);
+ t2_offset = t1_offset + 0x080;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t2_offset, 8,
+ dlys);
- if (NREV_LT(pi->pubpi.phy_rev, 2)) {
- write_phy_reg(pi, 0x180, 0xaa8);
- write_phy_reg(pi, 0x181, 0x9a4);
+ for (ctr = len; ctr < 16; ctr++) {
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
+ t1_offset + ctr, 8, &end_event);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
+ t2_offset + ctr, 8, &end_dly);
}
- if (PHY_IPA(pi)) {
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (1) << 0);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x298 :
- 0x29c, (0x1ff << 7),
- (pi->nphy_papd_epsilon_offset[core]) << 7);
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
- }
+static u16 wlc_phy_read_lpf_bw_ctl_nphy(struct brcms_phy *pi, u16 offset)
+{
+ u16 lpf_bw_ctl_val = 0;
+ u16 rx2tx_lpf_rc_lut_offset = 0;
- wlc_phy_ipa_set_tx_digi_filts_nphy(pi);
+ if (offset == 0) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ rx2tx_lpf_rc_lut_offset = 0x159;
+ else
+ rx2tx_lpf_rc_lut_offset = 0x154;
} else {
-
- if (NREV_GE(pi->pubpi.phy_rev, 5)) {
- wlc_phy_extpa_set_tx_digi_filts_nphy(pi);
- }
+ rx2tx_lpf_rc_lut_offset = offset;
}
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
+ (u32) rx2tx_lpf_rc_lut_offset, 16,
+ &lpf_bw_ctl_val);
- wlc_phy_workarounds_nphy(pi);
-
- wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
-
- val = read_phy_reg(pi, 0x01);
- write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA);
- write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA));
- wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
-
- wlapi_bmac_macphyclk_set(pi->sh->physhim, ON);
-
- wlc_phy_pa_override_nphy(pi, OFF);
- wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX);
- wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
- wlc_phy_pa_override_nphy(pi, ON);
+ lpf_bw_ctl_val = lpf_bw_ctl_val & 0x7;
- wlc_phy_classifier_nphy(pi, 0, 0);
- wlc_phy_clip_det_nphy(pi, 0, clip1_ths);
+ return lpf_bw_ctl_val;
+}
- if (CHSPEC_IS2G(pi->radio_chanspec))
- wlc_phy_bphy_init_nphy(pi);
+static void
+wlc_phy_rfctrl_override_nphy_rev7(struct brcms_phy *pi, u16 field, u16 value,
+ u8 core_mask, u8 off, u8 override_id)
+{
+ u8 core_num;
+ u16 addr = 0, en_addr = 0, val_addr = 0, en_mask = 0, val_mask = 0;
+ u8 val_shift = 0;
- tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
- wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ en_mask = field;
+ for (core_num = 0; core_num < 2; core_num++) {
+ if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID0) {
- wlc_phy_txpwr_fixpower_nphy(pi);
+ switch (field) {
+ case (0x1 << 2):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 5):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 5);
+ val_shift = 5;
+ break;
+ case (0x1 << 6):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 7):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a :
+ 0x7d;
+ val_mask = (0x1 << 7);
+ val_shift = 7;
+ break;
+ case (0x1 << 10):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf8 :
+ 0xfa;
+ val_mask = (0x7 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 11):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7b :
+ 0x7e;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 12):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7c :
+ 0x7f;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x3 << 13):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x348 :
+ 0x349;
+ val_mask = (0xff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 13):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x348 :
+ 0x349;
+ val_mask = (0xf << 0);
+ val_shift = 0;
+ break;
+ default:
+ addr = 0xffff;
+ break;
+ }
+ } else if (override_id ==
+ NPHY_REV7_RFCTRLOVERRIDE_ID1) {
- wlc_phy_txpwrctrl_idle_tssi_nphy(pi);
+ switch (field) {
+ case (0x1 << 1):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 3);
+ val_shift = 3;
+ break;
+ case (0x1 << 5):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 5);
+ val_shift = 5;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 2):
- wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 7):
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- u32 *tx_pwrctrl_tbl = NULL;
- u16 idx;
- s16 pga_gn = 0;
- s16 pad_gn = 0;
- s32 rfpwr_offset = 0;
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x7 << 8);
+ val_shift = 8;
+ break;
+ case (0x1 << 11):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 14);
+ val_shift = 14;
+ break;
+ case (0x1 << 10):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 13);
+ val_shift = 13;
+ break;
+ case (0x1 << 9):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 12);
+ val_shift = 12;
+ break;
+ case (0x1 << 8):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 11);
+ val_shift = 11;
+ break;
+ case (0x1 << 6):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 0):
+ en_addr = (core_num == 0) ? 0x342 :
+ 0x343;
+ val_addr = (core_num == 0) ? 0x340 :
+ 0x341;
+ val_mask = (0x1 << 0);
+ val_shift = 0;
+ break;
+ default:
+ addr = 0xffff;
+ break;
+ }
+ } else if (override_id ==
+ NPHY_REV7_RFCTRLOVERRIDE_ID2) {
- if (PHY_IPA(pi)) {
- tx_pwrctrl_tbl = wlc_phy_get_ipa_gaintbl_nphy(pi);
- } else {
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- if (NREV_IS(pi->pubpi.phy_rev, 3)) {
- tx_pwrctrl_tbl =
- nphy_tpc_5GHz_txgain_rev3;
- } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
- tx_pwrctrl_tbl =
- (pi->srom_fem5g.extpagain == 3) ?
- nphy_tpc_5GHz_txgain_HiPwrEPA :
- nphy_tpc_5GHz_txgain_rev4;
- } else {
- tx_pwrctrl_tbl =
- nphy_tpc_5GHz_txgain_rev5;
+ switch (field) {
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 3);
+ val_shift = 3;
+ break;
+ case (0x1 << 1):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 0):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 2):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0x346 :
+ 0x347;
+ val_addr = (core_num == 0) ? 0x344 :
+ 0x345;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ default:
+ addr = 0xffff;
+ break;
}
+ }
+ if (off) {
+ and_phy_reg(pi, en_addr, ~en_mask);
+ and_phy_reg(pi, val_addr, ~val_mask);
} else {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (pi->pubpi.radiorev == 5) {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_epa_2057rev5;
- } else if (pi->pubpi.radiorev == 3) {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_epa_2057rev3;
- }
- } else {
- if (NREV_GE(pi->pubpi.phy_rev, 5) &&
- (pi->srom_fem2g.extpagain == 3)) {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_HiPwrEPA;
- } else {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_rev3;
- }
+ if ((core_mask == 0)
+ || (core_mask & (1 << core_num))) {
+ or_phy_reg(pi, en_addr, en_mask);
+
+ if (addr != 0xffff)
+ mod_phy_reg(pi, val_addr,
+ val_mask,
+ (value <<
+ val_shift));
}
}
}
+ }
+}
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128,
- 192, 32, tx_pwrctrl_tbl);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128,
- 192, 32, tx_pwrctrl_tbl);
-
- pi->nphy_gmval = (u16) ((*tx_pwrctrl_tbl >> 16) & 0x7000);
+static void wlc_phy_adjust_lnagaintbl_nphy(struct brcms_phy *pi)
+{
+ uint core;
+ int ctr;
+ s16 gain_delta[2];
+ u8 curr_channel;
+ u16 minmax_gain[2];
+ u16 regval[4];
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
- for (idx = 0; idx < 128; idx++) {
- pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf;
- pad_gn = (tx_pwrctrl_tbl[idx] >> 19) & 0x1f;
+ if (pi->nphy_gain_boost) {
+ if ((CHSPEC_IS2G(pi->radio_chanspec))) {
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if ((pi->pubpi.radiorev == 3) ||
- (pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
- rfpwr_offset = (s16)
- nphy_papd_padgain_dlt_2g_2057rev3n4
- [pad_gn];
- } else if (pi->pubpi.radiorev == 5) {
- rfpwr_offset = (s16)
- nphy_papd_padgain_dlt_2g_2057rev5
- [pad_gn];
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev ==
- 8)) {
- rfpwr_offset = (s16)
- nphy_papd_padgain_dlt_2g_2057rev7
- [pad_gn];
- }
- } else {
- if ((pi->pubpi.radiorev == 3) ||
- (pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
- rfpwr_offset = (s16)
- nphy_papd_pgagain_dlt_5g_2057
- [pga_gn];
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev ==
- 8)) {
- rfpwr_offset = (s16)
- nphy_papd_pgagain_dlt_5g_2057rev7
- [pga_gn];
- }
- }
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_CORE1TXPWRCTL,
- 1, 576 + idx, 32,
- &rfpwr_offset);
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_CORE2TXPWRCTL,
- 1, 576 + idx, 32,
- &rfpwr_offset);
- }
+ gain_delta[0] = 6;
+ gain_delta[1] = 6;
} else {
- for (idx = 0; idx < 128; idx++) {
- pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf;
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- rfpwr_offset = (s16)
- nphy_papd_pga_gain_delta_ipa_2g
- [pga_gn];
- } else {
- rfpwr_offset = (s16)
- nphy_papd_pga_gain_delta_ipa_5g
- [pga_gn];
- }
-
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_CORE1TXPWRCTL,
- 1, 576 + idx, 32,
- &rfpwr_offset);
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_CORE2TXPWRCTL,
- 1, 576 + idx, 32,
- &rfpwr_offset);
- }
-
+ curr_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
+ gain_delta[0] =
+ (s16)
+ PHY_HW_ROUND(((nphy_lnagain_est0[0] *
+ curr_channel) +
+ nphy_lnagain_est0[1]), 13);
+ gain_delta[1] =
+ (s16)
+ PHY_HW_ROUND(((nphy_lnagain_est1[0] *
+ curr_channel) +
+ nphy_lnagain_est1[1]), 13);
}
} else {
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128,
- 192, 32, nphy_tpc_txgain);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128,
- 192, 32, nphy_tpc_txgain);
+ gain_delta[0] = 0;
+ gain_delta[1] = 0;
}
- if (pi->sh->phyrxchain != 0x3) {
- wlc_phy_rxcore_setstate_nphy((struct brcms_phy_pub *) pi,
- pi->sh->phyrxchain);
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (pi->nphy_elna_gain_config) {
+
+ regval[0] = nphy_def_lnagains[2] + gain_delta[core];
+ regval[1] = nphy_def_lnagains[3] + gain_delta[core];
+ regval[2] = nphy_def_lnagains[3] + gain_delta[core];
+ regval[3] = nphy_def_lnagains[3] + gain_delta[core];
+ } else {
+ for (ctr = 0; ctr < 4; ctr++)
+ regval[ctr] =
+ nphy_def_lnagains[ctr] +
+ gain_delta[core];
+ }
+ wlc_phy_table_write_nphy(pi, core, 4, 8, 16, regval);
+
+ minmax_gain[core] =
+ (u16) (nphy_def_lnagains[2] + gain_delta[core] + 4);
}
- if (PHY_PERICAL_MPHASE_PENDING(pi)) {
- wlc_phy_cal_perical_mphase_restart(pi);
+ mod_phy_reg(pi, 0x1e, (0xff << 0), (minmax_gain[0] << 0));
+ mod_phy_reg(pi, 0x34, (0xff << 0), (minmax_gain[1] << 0));
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void
+wlc_phy_war_force_trsw_to_R_cliplo_nphy(struct brcms_phy *pi, u8 core)
+{
+ if (core == PHY_CORE_0) {
+ write_phy_reg(pi, 0x38, 0x4);
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ write_phy_reg(pi, 0x37, 0x0060);
+ else
+ write_phy_reg(pi, 0x37, 0x1080);
+ } else if (core == PHY_CORE_1) {
+ write_phy_reg(pi, 0x2ae, 0x4);
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ write_phy_reg(pi, 0x2ad, 0x0060);
+ else
+ write_phy_reg(pi, 0x2ad, 0x1080);
}
+}
- if (!NORADIO_ENAB(pi->pubpi)) {
- bool do_rssi_cal = false;
+static void wlc_phy_war_txchain_upd_nphy(struct brcms_phy *pi, u8 txchain)
+{
+ u8 txchain0, txchain1;
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- do_rssi_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ?
- (pi->nphy_rssical_chanspec_2G == 0) :
- (pi->nphy_rssical_chanspec_5G == 0);
+ txchain0 = txchain & 0x1;
+ txchain1 = (txchain & 0x2) >> 1;
+ if (!txchain0)
+ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0);
- if (do_rssi_cal) {
- wlc_phy_rssi_cal_nphy(pi);
- } else {
- wlc_phy_restore_rssical_nphy(pi);
- }
- } else {
- wlc_phy_rssi_cal_nphy(pi);
- }
+ if (!txchain1)
+ wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1);
+}
- if (!SCAN_RM_IN_PROGRESS(pi)) {
- do_nphy_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ?
- (pi->nphy_iqcal_chanspec_2G == 0) :
- (pi->nphy_iqcal_chanspec_5G == 0);
- }
+static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi)
+{
+ s8 lna1_gain_db[] = { 8, 13, 17, 22 };
+ s8 lna2_gain_db[] = { -2, 7, 11, 15 };
+ s8 tia_gain_db[] = { -4, -1, 2, 5, 5, 5, 5, 5, 5, 5 };
+ s8 tia_gainbits[] = {
+ 0x0, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
- if (!pi->do_initcal)
- do_nphy_cal = false;
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
- if (do_nphy_cal) {
+ mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0));
- target_gain = wlc_phy_get_tx_gain_nphy(pi);
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x3c << 0));
+ mod_phy_reg(pi, 0x280, (0xff << 0), (0x3c << 0));
- if (pi->antsel_type == ANTSEL_2x3)
- wlc_phy_antsel_init((struct brcms_phy_pub *) pi,
- true);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x8, 8,
+ lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x8, 8,
+ lna1_gain_db);
- if (pi->nphy_perical != PHY_PERICAL_MPHASE) {
- wlc_phy_rssi_cal_nphy(pi);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, 8,
+ lna2_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, 8,
+ lna2_gain_db);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- pi->nphy_cal_orig_pwr_idx[0] =
- pi->nphy_txpwrindex[PHY_CORE_0].
- index_internal;
- pi->nphy_cal_orig_pwr_idx[1] =
- pi->nphy_txpwrindex[PHY_CORE_1].
- index_internal;
-
- wlc_phy_precal_txgain_nphy(pi);
- target_gain =
- wlc_phy_get_tx_gain_nphy(pi);
- }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8,
+ tia_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8,
+ tia_gain_db);
- if (wlc_phy_cal_txiqlo_nphy
- (pi, target_gain, true, false) == 0) {
- if (wlc_phy_cal_rxiq_nphy
- (pi, target_gain, 2,
- false) == 0) {
- wlc_phy_savecal_nphy(pi);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8,
+ tia_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8,
+ tia_gainbits);
- }
- }
- } else if (pi->mphase_cal_phase_id ==
- MPHASE_CAL_STATE_IDLE) {
+ write_phy_reg(pi, 0x37, 0x74);
+ write_phy_reg(pi, 0x2ad, 0x74);
+ write_phy_reg(pi, 0x38, 0x18);
+ write_phy_reg(pi, 0x2ae, 0x18);
- wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
- PHY_PERICAL_PHYINIT);
- }
- } else {
- wlc_phy_restorecal_nphy(pi);
- }
- }
+ write_phy_reg(pi, 0x2b, 0xe8);
+ write_phy_reg(pi, 0x41, 0xe8);
- wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
- wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state);
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (0x12 << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (0x12 << 0));
+ } else {
- wlc_phy_nphy_tkip_rifs_war(pi, pi->sh->_rifs_phy);
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (0x10 << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (0x10 << 0));
+ }
+}
- if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LE(pi->pubpi.phy_rev, 6))
+static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi)
+{
+ u16 currband;
+ s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 };
+ s8 *lna1_gain_db = NULL;
+ s8 *lna1_gain_db_2 = NULL;
+ s8 *lna2_gain_db = NULL;
+ s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 };
+ s8 *tia_gain_db;
+ s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 };
+ s8 *tia_gainbits;
+ u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f };
+ u16 *rfseq_init_gain;
+ u16 init_gaincode;
+ u16 clip1hi_gaincode;
+ u16 clip1md_gaincode = 0;
+ u16 clip1md_gaincode_B;
+ u16 clip1lo_gaincode;
+ u16 clip1lo_gaincode_B;
+ u8 crsminl_th = 0;
+ u8 crsminu_th;
+ u16 nbclip_th = 0;
+ u8 w1clip_th;
+ u16 freq;
+ s8 nvar_baseline_offset0 = 0, nvar_baseline_offset1 = 0;
+ u8 chg_nbclip_th = 0;
- write_phy_reg(pi, 0x70, 50);
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
- wlc_phy_txlpfbw_nphy(pi);
+ currband = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
+ if (currband == 0) {
- wlc_phy_spurwar_nphy(pi);
+ lna1_gain_db = lna1G_gain_db_rev7;
-}
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8,
+ lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8,
+ lna1_gain_db);
-static void wlc_phy_update_mimoconfig_nphy(struct brcms_phy *pi, s32 preamble)
-{
- bool gf_preamble = false;
- u16 val;
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x40 << 0));
- if (preamble == BRCMS_N_PREAMBLE_GF)
- gf_preamble = true;
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x280, (0xff << 0), (0x3e << 0));
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x3e << 0));
+ }
- val = read_phy_reg(pi, 0xed);
+ mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0));
- val |= RX_GF_MM_AUTO;
- val &= ~RX_GF_OR_MM;
- if (gf_preamble)
- val |= RX_GF_OR_MM;
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (13 << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (13 << 0));
+ }
+ } else {
- write_phy_reg(pi, 0xed, val);
-}
+ init_gaincode = 0x9e;
+ clip1hi_gaincode = 0x9e;
+ clip1md_gaincode_B = 0x24;
+ clip1lo_gaincode = 0x8a;
+ clip1lo_gaincode_B = 8;
+ rfseq_init_gain = rfseqA_init_gain_rev7;
-static void wlc_phy_resetcca_nphy(struct brcms_phy *pi)
-{
- u16 val;
+ tia_gain_db = tiaA_gain_db_rev7;
+ tia_gainbits = tiaA_gainbits_rev7;
- wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
+ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec));
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
- val = read_phy_reg(pi, 0x01);
- write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA);
- udelay(1);
- write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA));
+ w1clip_th = 25;
+ clip1md_gaincode = 0x82;
- wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
+ if ((freq <= 5080) || (freq == 5825)) {
- wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
-}
+ s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 };
+ s8 lna1A_gain_db_2_rev7[] = {
+ 11, 17, 22, 25};
+ s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
-void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en)
-{
- u16 rfctrlintc_override_val;
+ crsminu_th = 0x3e;
+ lna1_gain_db = lna1A_gain_db_rev7;
+ lna1_gain_db_2 = lna1A_gain_db_2_rev7;
+ lna2_gain_db = lna2A_gain_db_rev7;
+ } else if ((freq >= 5500) && (freq <= 5700)) {
- if (!en) {
+ s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 };
+ s8 lna1A_gain_db_2_rev7[] = {
+ 12, 18, 22, 26};
+ s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 };
- pi->rfctrlIntc1_save = read_phy_reg(pi, 0x91);
- pi->rfctrlIntc2_save = read_phy_reg(pi, 0x92);
+ crsminu_th = 0x45;
+ clip1md_gaincode_B = 0x14;
+ nbclip_th = 0xff;
+ chg_nbclip_th = 1;
+ lna1_gain_db = lna1A_gain_db_rev7;
+ lna1_gain_db_2 = lna1A_gain_db_2_rev7;
+ lna2_gain_db = lna2A_gain_db_rev7;
+ } else {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- rfctrlintc_override_val = 0x1480;
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- rfctrlintc_override_val =
- CHSPEC_IS5G(pi->radio_chanspec) ? 0x600 : 0x480;
+ s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 };
+ s8 lna1A_gain_db_2_rev7[] = {
+ 12, 18, 22, 26};
+ s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+
+ crsminu_th = 0x41;
+ lna1_gain_db = lna1A_gain_db_rev7;
+ lna1_gain_db_2 = lna1A_gain_db_2_rev7;
+ lna2_gain_db = lna2A_gain_db_rev7;
+ }
+
+ if (freq <= 4920) {
+ nvar_baseline_offset0 = 5;
+ nvar_baseline_offset1 = 5;
+ } else if ((freq > 4920) && (freq <= 5320)) {
+ nvar_baseline_offset0 = 3;
+ nvar_baseline_offset1 = 5;
+ } else if ((freq > 5320) && (freq <= 5700)) {
+ nvar_baseline_offset0 = 3;
+ nvar_baseline_offset1 = 2;
+ } else {
+ nvar_baseline_offset0 = 4;
+ nvar_baseline_offset1 = 0;
+ }
} else {
- rfctrlintc_override_val =
- CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120;
+
+ crsminu_th = 0x3a;
+ crsminl_th = 0x3a;
+ w1clip_th = 20;
+
+ if ((freq >= 4920) && (freq <= 5320)) {
+ nvar_baseline_offset0 = 4;
+ nvar_baseline_offset1 = 5;
+ } else if ((freq > 5320) && (freq <= 5550)) {
+ nvar_baseline_offset0 = 4;
+ nvar_baseline_offset1 = 2;
+ } else {
+ nvar_baseline_offset0 = 5;
+ nvar_baseline_offset1 = 3;
+ }
}
- write_phy_reg(pi, 0x91, rfctrlintc_override_val);
- write_phy_reg(pi, 0x92, rfctrlintc_override_val);
- } else {
+ write_phy_reg(pi, 0x20, init_gaincode);
+ write_phy_reg(pi, 0x2a7, init_gaincode);
- write_phy_reg(pi, 0x91, pi->rfctrlIntc1_save);
- write_phy_reg(pi, 0x92, pi->rfctrlIntc2_save);
- }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ pi->pubpi.phy_corenum, 0x106, 16,
+ rfseq_init_gain);
-}
+ write_phy_reg(pi, 0x22, clip1hi_gaincode);
+ write_phy_reg(pi, 0x2a9, clip1hi_gaincode);
-void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi)
-{
+ write_phy_reg(pi, 0x36, clip1md_gaincode_B);
+ write_phy_reg(pi, 0x2ac, clip1md_gaincode_B);
- u16 txrx_chain =
- (NPHY_RfseqCoreActv_TxRxChain0 | NPHY_RfseqCoreActv_TxRxChain1);
- bool CoreActv_override = false;
+ write_phy_reg(pi, 0x37, clip1lo_gaincode);
+ write_phy_reg(pi, 0x2ad, clip1lo_gaincode);
+ write_phy_reg(pi, 0x38, clip1lo_gaincode_B);
+ write_phy_reg(pi, 0x2ae, clip1lo_gaincode_B);
- if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN0) {
- txrx_chain = NPHY_RfseqCoreActv_TxRxChain0;
- CoreActv_override = true;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8,
+ tia_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8,
+ tia_gain_db);
- if (NREV_LE(pi->pubpi.phy_rev, 2)) {
- and_phy_reg(pi, 0xa0, ~0x20);
- }
- } else if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN1) {
- txrx_chain = NPHY_RfseqCoreActv_TxRxChain1;
- CoreActv_override = true;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8,
+ tia_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8,
+ tia_gainbits);
- if (NREV_LE(pi->pubpi.phy_rev, 2)) {
- or_phy_reg(pi, 0xa0, 0x20);
+ mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0));
+
+ if (chg_nbclip_th == 1) {
+ write_phy_reg(pi, 0x2b, nbclip_th);
+ write_phy_reg(pi, 0x41, nbclip_th);
}
- }
- mod_phy_reg(pi, 0xa2, ((0xf << 0) | (0xf << 4)), txrx_chain);
+ mod_phy_reg(pi, 0x300, (0x3f << 0), (w1clip_th << 0));
+ mod_phy_reg(pi, 0x301, (0x3f << 0), (w1clip_th << 0));
- if (CoreActv_override) {
+ mod_phy_reg(pi, 0x2e4,
+ (0x3f << 0), (nvar_baseline_offset0 << 0));
- pi->nphy_perical = PHY_PERICAL_DISABLE;
- or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override);
- } else {
- pi->nphy_perical = PHY_PERICAL_MPHASE;
- and_phy_reg(pi, 0xa1, ~NPHY_RfseqMode_CoreActv_override);
+ mod_phy_reg(pi, 0x2e4,
+ (0x3f << 6), (nvar_baseline_offset1 << 6));
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8,
+ lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8,
+ lna1_gain_db_2);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10,
+ 8, lna2_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10,
+ 8, lna2_gain_db);
+
+ write_phy_reg(pi, 0x24, clip1md_gaincode);
+ write_phy_reg(pi, 0x2ab, clip1md_gaincode);
+ } else {
+ mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0));
+ }
}
}
-void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
+static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi)
{
- u16 regval;
- u16 tbl_buf[16];
- uint i;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
- u16 tbl_opcode;
- bool suspend;
+ u16 w1th, hpf_code, currband;
+ int ctr;
+ u8 rfseq_updategainu_events[] = {
+ NPHY_RFSEQ_CMD_RX_GAIN,
+ NPHY_RFSEQ_CMD_CLR_HIQ_DIS,
+ NPHY_RFSEQ_CMD_SET_HPF_BW
+ };
+ u8 rfseq_updategainu_dlys[] = { 10, 30, 1 };
+ s8 lna1G_gain_db[] = { 7, 11, 16, 23 };
+ s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 };
+ s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 };
+ s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 };
+ s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 };
+ s8 lna1A_gain_db[] = { 7, 11, 17, 23 };
+ s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 };
+ s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 };
+ s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 };
+ s8 *lna1_gain_db = NULL;
+ s8 lna2G_gain_db[] = { -5, 6, 10, 14 };
+ s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 };
+ s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 };
+ s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 };
+ s8 lna2A_gain_db[] = { -6, 2, 6, 10 };
+ s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 };
+ s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 };
+ s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 };
+ s8 *lna2_gain_db = NULL;
+ s8 tiaG_gain_db[] = {
+ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A };
+ s8 tiaA_gain_db[] = {
+ 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 };
+ s8 tiaA_gain_db_rev4[] = {
+ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
+ s8 tiaA_gain_db_rev5[] = {
+ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
+ s8 tiaA_gain_db_rev6[] = {
+ 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
+ s8 *tia_gain_db;
+ s8 tiaG_gainbits[] = {
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
+ s8 tiaA_gainbits[] = {
+ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 };
+ s8 tiaA_gainbits_rev4[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ s8 tiaA_gainbits_rev5[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ s8 tiaA_gainbits_rev6[] = {
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
+ s8 *tia_gainbits;
+ s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 };
+ s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 };
+ u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f };
+ u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f };
+ u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f };
+ u16 rfseqG_init_gain_rev5_elna[] = {
+ 0x013f, 0x013f, 0x013f, 0x013f };
+ u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f };
+ u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f };
+ u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f };
+ u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f };
+ u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f };
+ u16 rfseqA_init_gain_rev4_elna[] = {
+ 0x314f, 0x314f, 0x314f, 0x314f };
+ u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f };
+ u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f };
+ u16 *rfseq_init_gain;
+ u16 initG_gaincode = 0x627e;
+ u16 initG_gaincode_rev4 = 0x527e;
+ u16 initG_gaincode_rev5 = 0x427e;
+ u16 initG_gaincode_rev5_elna = 0x027e;
+ u16 initG_gaincode_rev6 = 0x527e;
+ u16 initG_gaincode_rev6_224B0 = 0x427e;
+ u16 initG_gaincode_rev6_elna = 0x127e;
+ u16 initA_gaincode = 0x52de;
+ u16 initA_gaincode_rev4 = 0x629e;
+ u16 initA_gaincode_rev4_elna = 0x329e;
+ u16 initA_gaincode_rev5 = 0x729e;
+ u16 initA_gaincode_rev6 = 0x729e;
+ u16 init_gaincode;
+ u16 clip1hiG_gaincode = 0x107e;
+ u16 clip1hiG_gaincode_rev4 = 0x007e;
+ u16 clip1hiG_gaincode_rev5 = 0x1076;
+ u16 clip1hiG_gaincode_rev6 = 0x007e;
+ u16 clip1hiA_gaincode = 0x00de;
+ u16 clip1hiA_gaincode_rev4 = 0x029e;
+ u16 clip1hiA_gaincode_rev5 = 0x029e;
+ u16 clip1hiA_gaincode_rev6 = 0x029e;
+ u16 clip1hi_gaincode;
+ u16 clip1mdG_gaincode = 0x0066;
+ u16 clip1mdA_gaincode = 0x00ca;
+ u16 clip1mdA_gaincode_rev4 = 0x1084;
+ u16 clip1mdA_gaincode_rev5 = 0x2084;
+ u16 clip1mdA_gaincode_rev6 = 0x2084;
+ u16 clip1md_gaincode = 0;
+ u16 clip1loG_gaincode = 0x0074;
+ u16 clip1loG_gaincode_rev5[] = {
+ 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c
+ };
+ u16 clip1loG_gaincode_rev6[] = {
+ 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e
+ };
+ u16 clip1loG_gaincode_rev6_224B0 = 0x1074;
+ u16 clip1loA_gaincode = 0x00cc;
+ u16 clip1loA_gaincode_rev4 = 0x0086;
+ u16 clip1loA_gaincode_rev5 = 0x2086;
+ u16 clip1loA_gaincode_rev6 = 0x2086;
+ u16 clip1lo_gaincode;
+ u8 crsminG_th = 0x18;
+ u8 crsminG_th_rev5 = 0x18;
+ u8 crsminG_th_rev6 = 0x18;
+ u8 crsminA_th = 0x1e;
+ u8 crsminA_th_rev4 = 0x24;
+ u8 crsminA_th_rev5 = 0x24;
+ u8 crsminA_th_rev6 = 0x24;
+ u8 crsmin_th;
+ u8 crsminlG_th = 0x18;
+ u8 crsminlG_th_rev5 = 0x18;
+ u8 crsminlG_th_rev6 = 0x18;
+ u8 crsminlA_th = 0x1e;
+ u8 crsminlA_th_rev4 = 0x24;
+ u8 crsminlA_th_rev5 = 0x24;
+ u8 crsminlA_th_rev6 = 0x24;
+ u8 crsminl_th = 0;
+ u8 crsminuG_th = 0x18;
+ u8 crsminuG_th_rev5 = 0x18;
+ u8 crsminuG_th_rev6 = 0x18;
+ u8 crsminuA_th = 0x1e;
+ u8 crsminuA_th_rev4 = 0x24;
+ u8 crsminuA_th_rev5 = 0x24;
+ u8 crsminuA_th_rev6 = 0x24;
+ u8 crsminuA_th_rev6_224B0 = 0x2d;
+ u8 crsminu_th;
+ u16 nbclipG_th = 0x20d;
+ u16 nbclipG_th_rev4 = 0x1a1;
+ u16 nbclipG_th_rev5 = 0x1d0;
+ u16 nbclipG_th_rev6 = 0x1d0;
+ u16 nbclipA_th = 0x1a1;
+ u16 nbclipA_th_rev4 = 0x107;
+ u16 nbclipA_th_rev5 = 0x0a9;
+ u16 nbclipA_th_rev6 = 0x0f0;
+ u16 nbclip_th = 0;
+ u8 w1clipG_th = 5;
+ u8 w1clipG_th_rev5 = 9;
+ u8 w1clipG_th_rev6 = 5;
+ u8 w1clipA_th = 25, w1clip_th;
+ u8 rssi_gain_default = 0x50;
+ u8 rssiG_gain_rev6_224B0 = 0x50;
+ u8 rssiA_gain_rev5 = 0x90;
+ u8 rssiA_gain_rev6 = 0x90;
+ u8 rssi_gain;
+ u16 regval[21];
+ u8 triso;
- pi->sh->phyrxchain = rxcore_bitmask;
+ triso = (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.triso :
+ pi->srom_fem2g.triso;
- if (!pi->sh->clk)
- return;
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (pi->pubpi.radiorev == 5) {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev5(pi);
+ } else if (pi->pubpi.radiorev == 7) {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
- suspend =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
- if (!suspend)
- wlapi_suspend_mac_and_wait(pi->sh->physhim);
+ mod_phy_reg(pi, 0x283, (0xff << 0), (0x44 << 0));
+ mod_phy_reg(pi, 0x280, (0xff << 0), (0x44 << 0));
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
+ } else if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 8)) {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
- regval = read_phy_reg(pi, 0xa2);
- regval &= ~(0xf << 4);
- regval |= ((u16) (rxcore_bitmask & 0x3)) << 4;
- write_phy_reg(pi, 0xa2, regval);
+ if (pi->pubpi.radiorev == 8) {
+ mod_phy_reg(pi, 0x283,
+ (0xff << 0), (0x44 << 0));
+ mod_phy_reg(pi, 0x280,
+ (0xff << 0), (0x44 << 0));
+ }
+ } else {
+ wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
+ }
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if ((rxcore_bitmask & 0x3) != 0x3) {
+ mod_phy_reg(pi, 0xa0, (0x1 << 6), (1 << 6));
- write_phy_reg(pi, 0x20e, 1);
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if (pi->rx2tx_biasentry == -1) {
- wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ,
- ARRAY_SIZE(tbl_buf), 80,
- 16, tbl_buf);
+ currband =
+ read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
+ if (currband == 0) {
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ if (pi->pubpi.radiorev == 11) {
+ lna1_gain_db = lna1G_gain_db_rev6_224B0;
+ lna2_gain_db = lna2G_gain_db_rev6_224B0;
+ rfseq_init_gain =
+ rfseqG_init_gain_rev6_224B0;
+ init_gaincode =
+ initG_gaincode_rev6_224B0;
+ clip1hi_gaincode =
+ clip1hiG_gaincode_rev6;
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6_224B0;
+ nbclip_th = nbclipG_th_rev6;
+ w1clip_th = w1clipG_th_rev6;
+ crsmin_th = crsminG_th_rev6;
+ crsminl_th = crsminlG_th_rev6;
+ crsminu_th = crsminuG_th_rev6;
+ rssi_gain = rssiG_gain_rev6_224B0;
+ } else {
+ lna1_gain_db = lna1G_gain_db_rev6;
+ lna2_gain_db = lna2G_gain_db_rev6;
+ if (pi->sh->boardflags & BFL_EXTLNA) {
- for (i = 0; i < ARRAY_SIZE(tbl_buf); i++) {
- if (tbl_buf[i] ==
- NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS) {
+ rfseq_init_gain =
+ rfseqG_init_gain_rev6_elna;
+ init_gaincode =
+ initG_gaincode_rev6_elna;
+ } else {
+ rfseq_init_gain =
+ rfseqG_init_gain_rev6;
+ init_gaincode =
+ initG_gaincode_rev6;
+ }
+ clip1hi_gaincode =
+ clip1hiG_gaincode_rev6;
+ switch (triso) {
+ case 0:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [0];
+ break;
+ case 1:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [1];
+ break;
+ case 2:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [2];
+ break;
+ case 3:
+ default:
- pi->rx2tx_biasentry = (u8) i;
- tbl_opcode =
- NPHY_REV3_RFSEQ_CMD_NOP;
- wlc_phy_table_write_nphy(pi,
- NPHY_TBL_ID_RFSEQ,
- 1, i,
- 16,
- &tbl_opcode);
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [3];
break;
- } else if (tbl_buf[i] ==
- NPHY_REV3_RFSEQ_CMD_END) {
+ case 4:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [4];
+ break;
+ case 5:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [5];
+ break;
+ case 6:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [6];
+ break;
+ case 7:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev6
+ [7];
break;
}
+ nbclip_th = nbclipG_th_rev6;
+ w1clip_th = w1clipG_th_rev6;
+ crsmin_th = crsminG_th_rev6;
+ crsminl_th = crsminlG_th_rev6;
+ crsminu_th = crsminuG_th_rev6;
+ rssi_gain = rssi_gain_default;
+ }
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ lna1_gain_db = lna1G_gain_db_rev5;
+ lna2_gain_db = lna2G_gain_db_rev5;
+ if (pi->sh->boardflags & BFL_EXTLNA) {
+
+ rfseq_init_gain =
+ rfseqG_init_gain_rev5_elna;
+ init_gaincode =
+ initG_gaincode_rev5_elna;
+ } else {
+ rfseq_init_gain = rfseqG_init_gain_rev5;
+ init_gaincode = initG_gaincode_rev5;
}
+ clip1hi_gaincode = clip1hiG_gaincode_rev5;
+ switch (triso) {
+ case 0:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[0];
+ break;
+ case 1:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[1];
+ break;
+ case 2:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[2];
+ break;
+ case 3:
+
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[3];
+ break;
+ case 4:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[4];
+ break;
+ case 5:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[5];
+ break;
+ case 6:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[6];
+ break;
+ case 7:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[7];
+ break;
+ default:
+ clip1lo_gaincode =
+ clip1loG_gaincode_rev5[3];
+ break;
+ }
+ nbclip_th = nbclipG_th_rev5;
+ w1clip_th = w1clipG_th_rev5;
+ crsmin_th = crsminG_th_rev5;
+ crsminl_th = crsminlG_th_rev5;
+ crsminu_th = crsminuG_th_rev5;
+ rssi_gain = rssi_gain_default;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ lna1_gain_db = lna1G_gain_db_rev4;
+ lna2_gain_db = lna2G_gain_db;
+ rfseq_init_gain = rfseqG_init_gain_rev4;
+ init_gaincode = initG_gaincode_rev4;
+ clip1hi_gaincode = clip1hiG_gaincode_rev4;
+ clip1lo_gaincode = clip1loG_gaincode;
+ nbclip_th = nbclipG_th_rev4;
+ w1clip_th = w1clipG_th;
+ crsmin_th = crsminG_th;
+ crsminl_th = crsminlG_th;
+ crsminu_th = crsminuG_th;
+ rssi_gain = rssi_gain_default;
+ } else {
+ lna1_gain_db = lna1G_gain_db;
+ lna2_gain_db = lna2G_gain_db;
+ rfseq_init_gain = rfseqG_init_gain;
+ init_gaincode = initG_gaincode;
+ clip1hi_gaincode = clip1hiG_gaincode;
+ clip1lo_gaincode = clip1loG_gaincode;
+ nbclip_th = nbclipG_th;
+ w1clip_th = w1clipG_th;
+ crsmin_th = crsminG_th;
+ crsminl_th = crsminlG_th;
+ crsminu_th = crsminuG_th;
+ rssi_gain = rssi_gain_default;
}
- }
- } else {
+ tia_gain_db = tiaG_gain_db;
+ tia_gainbits = tiaG_gainbits;
+ clip1md_gaincode = clip1mdG_gaincode;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ lna1_gain_db = lna1A_gain_db_rev6;
+ lna2_gain_db = lna2A_gain_db_rev6;
+ tia_gain_db = tiaA_gain_db_rev6;
+ tia_gainbits = tiaA_gainbits_rev6;
+ rfseq_init_gain = rfseqA_init_gain_rev6;
+ init_gaincode = initA_gaincode_rev6;
+ clip1hi_gaincode = clip1hiA_gaincode_rev6;
+ clip1md_gaincode = clip1mdA_gaincode_rev6;
+ clip1lo_gaincode = clip1loA_gaincode_rev6;
+ crsmin_th = crsminA_th_rev6;
+ crsminl_th = crsminlA_th_rev6;
+ if ((pi->pubpi.radiorev == 11) &&
+ (CHSPEC_IS40(pi->radio_chanspec) == 0))
+ crsminu_th = crsminuA_th_rev6_224B0;
+ else
+ crsminu_th = crsminuA_th_rev6;
- write_phy_reg(pi, 0x20e, 30);
+ nbclip_th = nbclipA_th_rev6;
+ rssi_gain = rssiA_gain_rev6;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ lna1_gain_db = lna1A_gain_db_rev5;
+ lna2_gain_db = lna2A_gain_db_rev5;
+ tia_gain_db = tiaA_gain_db_rev5;
+ tia_gainbits = tiaA_gainbits_rev5;
+ rfseq_init_gain = rfseqA_init_gain_rev5;
+ init_gaincode = initA_gaincode_rev5;
+ clip1hi_gaincode = clip1hiA_gaincode_rev5;
+ clip1md_gaincode = clip1mdA_gaincode_rev5;
+ clip1lo_gaincode = clip1loA_gaincode_rev5;
+ crsmin_th = crsminA_th_rev5;
+ crsminl_th = crsminlA_th_rev5;
+ crsminu_th = crsminuA_th_rev5;
+ nbclip_th = nbclipA_th_rev5;
+ rssi_gain = rssiA_gain_rev5;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
+ lna1_gain_db = lna1A_gain_db_rev4;
+ lna2_gain_db = lna2A_gain_db_rev4;
+ tia_gain_db = tiaA_gain_db_rev4;
+ tia_gainbits = tiaA_gainbits_rev4;
+ if (pi->sh->boardflags & BFL_EXTLNA_5GHz) {
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if (pi->rx2tx_biasentry != -1) {
- tbl_opcode = NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1, pi->rx2tx_biasentry,
- 16, &tbl_opcode);
- pi->rx2tx_biasentry = -1;
+ rfseq_init_gain =
+ rfseqA_init_gain_rev4_elna;
+ init_gaincode =
+ initA_gaincode_rev4_elna;
+ } else {
+ rfseq_init_gain = rfseqA_init_gain_rev4;
+ init_gaincode = initA_gaincode_rev4;
+ }
+ clip1hi_gaincode = clip1hiA_gaincode_rev4;
+ clip1md_gaincode = clip1mdA_gaincode_rev4;
+ clip1lo_gaincode = clip1loA_gaincode_rev4;
+ crsmin_th = crsminA_th_rev4;
+ crsminl_th = crsminlA_th_rev4;
+ crsminu_th = crsminuA_th_rev4;
+ nbclip_th = nbclipA_th_rev4;
+ rssi_gain = rssi_gain_default;
+ } else {
+ lna1_gain_db = lna1A_gain_db;
+ lna2_gain_db = lna2A_gain_db;
+ tia_gain_db = tiaA_gain_db;
+ tia_gainbits = tiaA_gainbits;
+ rfseq_init_gain = rfseqA_init_gain;
+ init_gaincode = initA_gaincode;
+ clip1hi_gaincode = clip1hiA_gaincode;
+ clip1md_gaincode = clip1mdA_gaincode;
+ clip1lo_gaincode = clip1loA_gaincode;
+ crsmin_th = crsminA_th;
+ crsminl_th = crsminlA_th;
+ crsminu_th = crsminuA_th;
+ nbclip_th = nbclipA_th;
+ rssi_gain = rssi_gain_default;
}
+ w1clip_th = w1clipA_th;
}
- }
- wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC |
+ RADIO_2056_RX0), 0x17);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC |
+ RADIO_2056_RX1), 0x17);
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
+ write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX0),
+ 0xf0);
+ write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX1),
+ 0xf0);
- if (!suspend)
- wlapi_enable_mac(pi->sh->physhim);
-}
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX0),
+ 0x0);
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX1),
+ 0x0);
-u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih)
-{
- u16 regval, rxen_bits;
- struct brcms_phy *pi = (struct brcms_phy *) pih;
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX0),
+ rssi_gain);
+ write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX1),
+ rssi_gain);
- regval = read_phy_reg(pi, 0xa2);
- rxen_bits = (regval >> 4) & 0xf;
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC |
+ RADIO_2056_RX0), 0x17);
+ write_radio_reg(pi,
+ (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC |
+ RADIO_2056_RX1), 0x17);
- return (u8) rxen_bits;
-}
+ write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX0),
+ 0xFF);
+ write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX1),
+ 0xFF);
-bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi)
-{
- return PHY_IPA(pi);
-}
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8,
+ 8, lna1_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8,
+ 8, lna1_gain_db);
-static void wlc_phy_txpwr_limit_to_tbl_nphy(struct brcms_phy *pi)
-{
- u8 idx, idx2, i, delta_ind;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10,
+ 8, lna2_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10,
+ 8, lna2_gain_db);
- for (idx = TXP_FIRST_CCK; idx <= TXP_LAST_CCK; idx++) {
- pi->adj_pwr_tbl_nphy[idx] = pi->tx_power_offset[idx];
- }
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20,
+ 8, tia_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20,
+ 8, tia_gain_db);
- for (i = 0; i < 4; i++) {
- idx2 = 0;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20,
+ 8, tia_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20,
+ 8, tia_gainbits);
- delta_ind = 0;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 6, 0x40,
+ 8, &lpf_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 6, 0x40,
+ 8, &lpf_gain_db);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 6, 0x40,
+ 8, &lpf_gainbits);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 6, 0x40,
+ 8, &lpf_gainbits);
- switch (i) {
- case 0:
+ write_phy_reg(pi, 0x20, init_gaincode);
+ write_phy_reg(pi, 0x2a7, init_gaincode);
- if (CHSPEC_IS40(pi->radio_chanspec)
- && NPHY_IS_SROM_REINTERPRET) {
- idx = TXP_FIRST_MCS_40_SISO;
- } else {
- idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
- TXP_FIRST_OFDM_40_SISO : TXP_FIRST_OFDM;
- delta_ind = 1;
- }
- break;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ pi->pubpi.phy_corenum, 0x106, 16,
+ rfseq_init_gain);
- case 1:
+ write_phy_reg(pi, 0x22, clip1hi_gaincode);
+ write_phy_reg(pi, 0x2a9, clip1hi_gaincode);
- idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
- TXP_FIRST_MCS_40_CDD : TXP_FIRST_MCS_20_CDD;
- break;
+ write_phy_reg(pi, 0x24, clip1md_gaincode);
+ write_phy_reg(pi, 0x2ab, clip1md_gaincode);
- case 2:
+ write_phy_reg(pi, 0x37, clip1lo_gaincode);
+ write_phy_reg(pi, 0x2ad, clip1lo_gaincode);
- idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
- TXP_FIRST_MCS_40_STBC : TXP_FIRST_MCS_20_STBC;
- break;
+ mod_phy_reg(pi, 0x27d, (0xff << 0), (crsmin_th << 0));
+ mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0));
+ mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0));
- case 3:
+ write_phy_reg(pi, 0x2b, nbclip_th);
+ write_phy_reg(pi, 0x41, nbclip_th);
- idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
- TXP_FIRST_MCS_40_SDM : TXP_FIRST_MCS_20_SDM;
- break;
+ mod_phy_reg(pi, 0x27, (0x3f << 0), (w1clip_th << 0));
+ mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1clip_th << 0));
+
+ write_phy_reg(pi, 0x150, 0x809c);
+
+ } else {
+
+ mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
+ mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+
+ write_phy_reg(pi, 0x2b, 0x84);
+ write_phy_reg(pi, 0x41, 0x84);
+
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+ write_phy_reg(pi, 0x6b, 0x2b);
+ write_phy_reg(pi, 0x6c, 0x2b);
+ write_phy_reg(pi, 0x6d, 0x9);
+ write_phy_reg(pi, 0x6e, 0x9);
}
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- idx = idx + delta_ind;
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx++];
+ w1th = NPHY_RSSICAL_W1_TARGET - 4;
+ mod_phy_reg(pi, 0x27, (0x3f << 0), (w1th << 0));
+ mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1th << 0));
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx++];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx++];
+ if (CHSPEC_IS20(pi->radio_chanspec)) {
+ mod_phy_reg(pi, 0x1c, (0x1f << 0), (0x1 << 0));
+ mod_phy_reg(pi, 0x32, (0x1f << 0), (0x1 << 0));
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx++];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx++];
+ mod_phy_reg(pi, 0x1d, (0x1f << 0), (0x1 << 0));
+ mod_phy_reg(pi, 0x33, (0x1f << 0), (0x1 << 0));
+ }
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx++];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- idx = idx + 1 - delta_ind;
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
+ write_phy_reg(pi, 0x150, 0x809c);
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
- pi->tx_power_offset[idx];
- }
-}
+ if (pi->nphy_gain_boost)
+ if ((CHSPEC_IS2G(pi->radio_chanspec)) &&
+ (CHSPEC_IS40(pi->radio_chanspec)))
+ hpf_code = 4;
+ else
+ hpf_code = 5;
+ else if (CHSPEC_IS40(pi->radio_chanspec))
+ hpf_code = 6;
+ else
+ hpf_code = 7;
-void wlc_phy_cal_init_nphy(struct brcms_phy *pi)
-{
-}
+ mod_phy_reg(pi, 0x20, (0x1f << 7), (hpf_code << 7));
+ mod_phy_reg(pi, 0x36, (0x1f << 7), (hpf_code << 7));
-static void
-wlc_phy_war_force_trsw_to_R_cliplo_nphy(struct brcms_phy *pi, u8 core)
-{
- if (core == PHY_CORE_0) {
- write_phy_reg(pi, 0x38, 0x4);
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- write_phy_reg(pi, 0x37, 0x0060);
- } else {
- write_phy_reg(pi, 0x37, 0x1080);
+ for (ctr = 0; ctr < 4; ctr++)
+ regval[ctr] = (hpf_code << 8) | 0x7c;
+ wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval);
+
+ wlc_phy_adjust_lnagaintbl_nphy(pi);
+
+ if (pi->nphy_elna_gain_config) {
+ regval[0] = 0;
+ regval[1] = 1;
+ regval[2] = 1;
+ regval[3] = 1;
+ wlc_phy_table_write_nphy(pi, 2, 4, 8, 16, regval);
+ wlc_phy_table_write_nphy(pi, 3, 4, 8, 16, regval);
+
+ for (ctr = 0; ctr < 4; ctr++)
+ regval[ctr] = (hpf_code << 8) | 0x74;
+ wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval);
}
- } else if (core == PHY_CORE_1) {
- write_phy_reg(pi, 0x2ae, 0x4);
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- write_phy_reg(pi, 0x2ad, 0x0060);
- } else {
- write_phy_reg(pi, 0x2ad, 0x1080);
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2)) {
+ for (ctr = 0; ctr < 21; ctr++)
+ regval[ctr] = 3 * ctr;
+ wlc_phy_table_write_nphy(pi, 0, 21, 32, 16, regval);
+ wlc_phy_table_write_nphy(pi, 1, 21, 32, 16, regval);
+
+ for (ctr = 0; ctr < 21; ctr++)
+ regval[ctr] = (u16) ctr;
+ wlc_phy_table_write_nphy(pi, 2, 21, 32, 16, regval);
+ wlc_phy_table_write_nphy(pi, 3, 21, 32, 16, regval);
}
- }
-}
-static void wlc_phy_war_txchain_upd_nphy(struct brcms_phy *pi, u8 txchain)
-{
- u8 txchain0, txchain1;
+ wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_UPDATEGAINU,
+ rfseq_updategainu_events,
+ rfseq_updategainu_dlys,
+ sizeof(rfseq_updategainu_events) /
+ sizeof(rfseq_updategainu_events[0]));
- txchain0 = txchain & 0x1;
- txchain1 = (txchain & 0x2) >> 1;
- if (!txchain0) {
- wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0);
- }
+ mod_phy_reg(pi, 0x153, (0xff << 8), (90 << 8));
- if (!txchain1) {
- wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1);
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ mod_phy_reg(pi,
+ (NPHY_TO_BPHY_OFF + BPHY_OPTIONAL_MODES),
+ 0x7f, 0x4);
}
}
@@ -15362,11 +16312,10 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
u16 freq;
int coreNum;
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 0);
- } else {
+ else
wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 1);
- }
if (pi->phyhang_avoid)
wlc_phy_stay_in_carriersearch_nphy(pi, true);
@@ -15401,9 +16350,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
write_phy_reg(pi, 0x240, 0x1b0);
}
- if (NREV_GE(pi->pubpi.phy_rev, 8)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 8))
mod_phy_reg(pi, 0xbd, (0xff << 0), (114 << 0));
- }
wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16,
&dac_control);
@@ -15422,7 +16370,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x16e, 16,
rfseq_rx2tx_dacbufpu_rev7);
- if (PHY_IPA(pi)) {
+ if (PHY_IPA(pi))
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
rfseq_rx2tx_events_rev3_ipa,
rfseq_rx2tx_dlys_rev3_ipa,
@@ -15431,7 +16379,6 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
sizeof
(rfseq_rx2tx_events_rev3_ipa
[0]));
- }
mod_phy_reg(pi, 0x299, (0x3 << 14), (0x1 << 14));
mod_phy_reg(pi, 0x29d, (0x3 << 14), (0x1 << 14));
@@ -15448,11 +16395,13 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
|| (pi->pubpi.radiorev == 8)) {
rccal_bcap_val =
- read_radio_reg(pi,
- RADIO_2057_RCCAL_BCAP_VAL);
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_BCAP_VAL);
rccal_scap_val =
- read_radio_reg(pi,
- RADIO_2057_RCCAL_SCAP_VAL);
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_SCAP_VAL);
rccal_tx20_11b_bcap = rccal_bcap_val;
rccal_tx20_11b_scap = rccal_scap_val;
@@ -15497,11 +16446,13 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
tx_lpf_bw_ofdm_40mhz = 3;
rccal_bcap_val =
- read_radio_reg(pi,
- RADIO_2057_RCCAL_BCAP_VAL);
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_BCAP_VAL);
rccal_scap_val =
- read_radio_reg(pi,
- RADIO_2057_RCCAL_SCAP_VAL);
+ read_radio_reg(
+ pi,
+ RADIO_2057_RCCAL_SCAP_VAL);
rccal_tx20_11b_bcap = rccal_bcap_val;
rccal_tx20_11b_scap = rccal_scap_val;
@@ -15517,70 +16468,83 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
if (rccal_ovrd) {
- rx2tx_lpf_rc_lut_tx20_11b = (rccal_tx20_11b_bcap << 8) |
- (rccal_tx20_11b_scap << 3) | tx_lpf_bw_11b;
- rx2tx_lpf_rc_lut_tx20_11n = (rccal_tx20_11n_bcap << 8) |
- (rccal_tx20_11n_scap << 3) | tx_lpf_bw_ofdm_20mhz;
- rx2tx_lpf_rc_lut_tx40_11n = (rccal_tx40_11n_bcap << 8) |
- (rccal_tx40_11n_scap << 3) | tx_lpf_bw_ofdm_40mhz;
+ rx2tx_lpf_rc_lut_tx20_11b =
+ (rccal_tx20_11b_bcap << 8) |
+ (rccal_tx20_11b_scap << 3) |
+ tx_lpf_bw_11b;
+ rx2tx_lpf_rc_lut_tx20_11n =
+ (rccal_tx20_11n_bcap << 8) |
+ (rccal_tx20_11n_scap << 3) |
+ tx_lpf_bw_ofdm_20mhz;
+ rx2tx_lpf_rc_lut_tx40_11n =
+ (rccal_tx40_11n_bcap << 8) |
+ (rccal_tx40_11n_scap << 3) |
+ tx_lpf_bw_ofdm_40mhz;
for (coreNum = 0; coreNum <= 1; coreNum++) {
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x152 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx20_11b);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x153 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx20_11n);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x154 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx20_11n);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x155 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx40_11n);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x156 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx40_11n);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x157 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx40_11n);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x158 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx40_11n);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- 1,
- 0x159 + coreNum * 0x10,
- 16,
- &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x152 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx20_11b);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x153 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx20_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x154 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx20_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x155 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x156 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x157 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x158 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_RFSEQ,
+ 1,
+ 0x159 + coreNum * 0x10,
+ 16,
+ &rx2tx_lpf_rc_lut_tx40_11n);
}
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4),
- 1, 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4),
+ 1, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
}
- if (!NORADIO_ENAB(pi->pubpi)) {
- write_phy_reg(pi, 0x32f, 0x3);
- }
+ write_phy_reg(pi, 0x32f, 0x3);
- if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2),
- 1, 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- }
+ if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ 1, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
if ((pi->pubpi.radiorev == 3) || (pi->pubpi.radiorev == 4) ||
(pi->pubpi.radiorev == 6)) {
@@ -15635,17 +16599,16 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
if (CHSPEC_IS2G(pi->radio_chanspec)) {
if ((pi->pubpi.radiorev == 3)
|| (pi->pubpi.radiorev == 4)
- || (pi->pubpi.radiorev == 6)) {
-
+ || (pi->pubpi.radiorev == 6))
txgm_idac_bleed = 0x7f;
- }
for (coreNum = 0; coreNum <= 1; coreNum++) {
if (txgm_idac_bleed != 0)
- WRITE_RADIO_REG4(pi, RADIO_2057,
- CORE, coreNum,
- TXGM_IDAC_BLEED,
- txgm_idac_bleed);
+ WRITE_RADIO_REG4(
+ pi, RADIO_2057,
+ CORE, coreNum,
+ TXGM_IDAC_BLEED,
+ txgm_idac_bleed);
}
if (pi->pubpi.radiorev == 5) {
@@ -15660,18 +16623,20 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
CORE, coreNum,
IPA2G_IMAIN,
0x1f);
- WRITE_RADIO_REG4(pi, RADIO_2057,
- CORE, coreNum,
- IPA2G_BIAS_FILTER,
- 0xee);
+ WRITE_RADIO_REG4(
+ pi, RADIO_2057,
+ CORE, coreNum,
+ IPA2G_BIAS_FILTER,
+ 0xee);
WRITE_RADIO_REG4(pi, RADIO_2057,
CORE, coreNum,
PAD2G_IDACS,
0x8a);
- WRITE_RADIO_REG4(pi, RADIO_2057,
- CORE, coreNum,
- PAD_BIAS_FILTER_BWS,
- 0x3e);
+ WRITE_RADIO_REG4(
+ pi, RADIO_2057,
+ CORE, coreNum,
+ PAD_BIAS_FILTER_BWS,
+ 0x3e);
}
} else if ((pi->pubpi.radiorev == 7)
@@ -15700,9 +16665,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
}
} else {
- freq =
- CHAN5G_FREQ(CHSPEC_CHANNEL
- (pi->radio_chanspec));
+ freq = CHAN5G_FREQ(CHSPEC_CHANNEL(
+ pi->radio_chanspec));
if (((freq >= 5180) && (freq <= 5230))
|| ((freq >= 5745) && (freq <= 5805))) {
WRITE_RADIO_REG4(pi, RADIO_2057, CORE,
@@ -15809,12 +16773,12 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
wlc_phy_workarounds_nphy_gainctrl(pi);
pdetrange =
- (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
- pdetrange : pi->srom_fem2g.pdetrange;
+ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
+ pdetrange : pi->srom_fem2g.pdetrange;
if (pdetrange == 0) {
chan_freq_range =
- wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
aux_adc_vmid_rev7_core0[3] = 0x70;
aux_adc_vmid_rev7_core1[3] = 0x70;
@@ -15842,15 +16806,15 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
if (chan_freq_range ==
WL_CHAN_FREQ_RANGE_2G) {
aux_adc_vmid_rev7_core0[3] =
- 0x8c;
+ 0x8c;
aux_adc_vmid_rev7_core1[3] =
- 0x8c;
+ 0x8c;
aux_adc_gain_rev7[3] = 0;
} else {
aux_adc_vmid_rev7_core0[3] =
- 0x96;
+ 0x96;
aux_adc_vmid_rev7_core1[3] =
- 0x96;
+ 0x96;
aux_adc_gain_rev7[3] = 0;
}
}
@@ -15918,7 +16882,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
sizeof(rfseq_tx2rx_events_rev3) /
sizeof(rfseq_tx2rx_events_rev3[0]));
- if (PHY_IPA(pi)) {
+ if (PHY_IPA(pi))
wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
rfseq_rx2tx_events_rev3_ipa,
rfseq_rx2tx_dlys_rev3_ipa,
@@ -15927,7 +16891,6 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
sizeof
(rfseq_rx2tx_events_rev3_ipa
[0]));
- }
if ((pi->sh->hw_phyrxchain != 0x3) &&
(pi->sh->hw_phyrxchain != pi->sh->hw_phytxchain)) {
@@ -15936,22 +16899,21 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
rfseq_rx2tx_dlys_rev3[5] = 59;
rfseq_rx2tx_dlys_rev3[6] = 1;
rfseq_rx2tx_events_rev3[7] =
- NPHY_REV3_RFSEQ_CMD_END;
+ NPHY_REV3_RFSEQ_CMD_END;
}
- wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX,
- rfseq_rx2tx_events_rev3,
- rfseq_rx2tx_dlys_rev3,
- sizeof(rfseq_rx2tx_events_rev3) /
- sizeof(rfseq_rx2tx_events_rev3
- [0]));
+ wlc_phy_set_rfseq_nphy(
+ pi, NPHY_RFSEQ_RX2TX,
+ rfseq_rx2tx_events_rev3,
+ rfseq_rx2tx_dlys_rev3,
+ sizeof(rfseq_rx2tx_events_rev3) /
+ sizeof(rfseq_rx2tx_events_rev3[0]));
}
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
write_phy_reg(pi, 0x6a, 0x2);
- } else {
+ else
write_phy_reg(pi, 0x6a, 0x9c40);
- }
mod_phy_reg(pi, 0x294, (0xf << 8), (7 << 8));
@@ -15978,8 +16940,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
&dac_control);
pdetrange =
- (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
- pdetrange : pi->srom_fem2g.pdetrange;
+ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
+ pdetrange : pi->srom_fem2g.pdetrange;
if (pdetrange == 0) {
if (NREV_GE(pi->pubpi.phy_rev, 4)) {
@@ -15990,7 +16952,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
aux_adc_gain = aux_adc_gain_rev3;
}
chan_freq_range =
- wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
switch (chan_freq_range) {
case WL_CHAN_FREQ_RANGE_5GL:
@@ -16033,7 +16995,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
if (NREV_GE(pi->pubpi.phy_rev, 6)) {
chan_freq_range =
- wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
bcm_adc_vmid[3] = 0x8e;
bcm_adc_gain[3] = 0x03;
@@ -16056,14 +17018,16 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
0x1c, 16, bcm_adc_gain);
} else if (pdetrange == 3) {
chan_freq_range =
- wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
if ((NREV_GE(pi->pubpi.phy_rev, 4))
&& (chan_freq_range == WL_CHAN_FREQ_RANGE_2G)) {
u16 auxadc_vmid[] = {
- 0xa2, 0xb4, 0xb4, 0x270 };
+ 0xa2, 0xb4, 0xb4, 0x270
+ };
u16 auxadc_gain[] = {
- 0x02, 0x02, 0x02, 0x00 };
+ 0x02, 0x02, 0x02, 0x00
+ };
wlc_phy_table_write_nphy(pi,
NPHY_TBL_ID_AFECTRL, 4,
@@ -16084,7 +17048,7 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
u16 Vmid[2], Av[2];
chan_freq_range =
- wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ wlc_phy_get_chan_freq_range_nphy(pi, 0);
if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) {
Vmid[0] = (pdetrange == 4) ? 0x8e : 0x89;
Vmid[1] = (pdetrange == 4) ? 0x96 : 0x89;
@@ -16155,8 +17119,8 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
0x0);
triso =
- (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
- triso : pi->srom_fem2g.triso;
+ (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.
+ triso : pi->srom_fem2g.triso;
if (triso == 7) {
wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0);
wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1);
@@ -16212,11 +17176,10 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
if (NREV_GE(pi->pubpi.phy_rev, 6)) {
- if (pi->sh->boardflags2 & BFL2_SINGLEANT_CCK) {
+ if (pi->sh->boardflags2 & BFL2_SINGLEANT_CCK)
wlapi_bmac_mhf(pi->sh->physhim, MHF4,
- MHF4_BPHY_TXCORE0,
- MHF4_BPHY_TXCORE0, BRCM_BAND_ALL);
- }
+ MHF4_BPHY_TXCORE0,
+ MHF4_BPHY_TXCORE0, BRCM_BAND_ALL);
}
} else {
@@ -16314,1121 +17277,2720 @@ static void wlc_phy_workarounds_nphy(struct brcms_phy *pi)
write_phy_reg(pi, 0x194, 0x0);
}
- if (NREV_IS(pi->pubpi.phy_rev, 2)) {
+ if (NREV_IS(pi->pubpi.phy_rev, 2))
mod_phy_reg(pi, 0x221,
NPHY_FORCESIG_DECODEGATEDCLKS,
NPHY_FORCESIG_DECODEGATEDCLKS);
- }
}
if (pi->phyhang_avoid)
wlc_phy_stay_in_carriersearch_nphy(pi, false);
}
-static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi)
+static void wlc_phy_extpa_set_tx_digi_filts_nphy(struct brcms_phy *pi)
{
- u16 w1th, hpf_code, currband;
- int ctr;
- u8 rfseq_updategainu_events[] = {
- NPHY_RFSEQ_CMD_RX_GAIN,
- NPHY_RFSEQ_CMD_CLR_HIQ_DIS,
- NPHY_RFSEQ_CMD_SET_HPF_BW
- };
- u8 rfseq_updategainu_dlys[] = { 10, 30, 1 };
- s8 lna1G_gain_db[] = { 7, 11, 16, 23 };
- s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 };
- s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 };
- s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 };
- s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 };
- s8 lna1A_gain_db[] = { 7, 11, 17, 23 };
- s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 };
- s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 };
- s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 };
- s8 *lna1_gain_db = NULL;
- s8 lna2G_gain_db[] = { -5, 6, 10, 14 };
- s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 };
- s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 };
- s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 };
- s8 lna2A_gain_db[] = { -6, 2, 6, 10 };
- s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 };
- s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 };
- s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 };
- s8 *lna2_gain_db = NULL;
- s8 tiaG_gain_db[] = {
- 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A };
- s8 tiaA_gain_db[] = {
- 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 };
- s8 tiaA_gain_db_rev4[] = {
- 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
- s8 tiaA_gain_db_rev5[] = {
- 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
- s8 tiaA_gain_db_rev6[] = {
- 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d };
- s8 *tia_gain_db;
- s8 tiaG_gainbits[] = {
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
- s8 tiaA_gainbits[] = {
- 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 };
- s8 tiaA_gainbits_rev4[] = {
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
- s8 tiaA_gainbits_rev5[] = {
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
- s8 tiaA_gainbits_rev6[] = {
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
- s8 *tia_gainbits;
- s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 };
- s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 };
- u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f };
- u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f };
- u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f };
- u16 rfseqG_init_gain_rev5_elna[] = {
- 0x013f, 0x013f, 0x013f, 0x013f };
- u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f };
- u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f };
- u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f };
- u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f };
- u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f };
- u16 rfseqA_init_gain_rev4_elna[] = {
- 0x314f, 0x314f, 0x314f, 0x314f };
- u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f };
- u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f };
- u16 *rfseq_init_gain;
- u16 initG_gaincode = 0x627e;
- u16 initG_gaincode_rev4 = 0x527e;
- u16 initG_gaincode_rev5 = 0x427e;
- u16 initG_gaincode_rev5_elna = 0x027e;
- u16 initG_gaincode_rev6 = 0x527e;
- u16 initG_gaincode_rev6_224B0 = 0x427e;
- u16 initG_gaincode_rev6_elna = 0x127e;
- u16 initA_gaincode = 0x52de;
- u16 initA_gaincode_rev4 = 0x629e;
- u16 initA_gaincode_rev4_elna = 0x329e;
- u16 initA_gaincode_rev5 = 0x729e;
- u16 initA_gaincode_rev6 = 0x729e;
- u16 init_gaincode;
- u16 clip1hiG_gaincode = 0x107e;
- u16 clip1hiG_gaincode_rev4 = 0x007e;
- u16 clip1hiG_gaincode_rev5 = 0x1076;
- u16 clip1hiG_gaincode_rev6 = 0x007e;
- u16 clip1hiA_gaincode = 0x00de;
- u16 clip1hiA_gaincode_rev4 = 0x029e;
- u16 clip1hiA_gaincode_rev5 = 0x029e;
- u16 clip1hiA_gaincode_rev6 = 0x029e;
- u16 clip1hi_gaincode;
- u16 clip1mdG_gaincode = 0x0066;
- u16 clip1mdA_gaincode = 0x00ca;
- u16 clip1mdA_gaincode_rev4 = 0x1084;
- u16 clip1mdA_gaincode_rev5 = 0x2084;
- u16 clip1mdA_gaincode_rev6 = 0x2084;
- u16 clip1md_gaincode = 0;
- u16 clip1loG_gaincode = 0x0074;
- u16 clip1loG_gaincode_rev5[] = {
- 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c
- };
- u16 clip1loG_gaincode_rev6[] = {
- 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e
- };
- u16 clip1loG_gaincode_rev6_224B0 = 0x1074;
- u16 clip1loA_gaincode = 0x00cc;
- u16 clip1loA_gaincode_rev4 = 0x0086;
- u16 clip1loA_gaincode_rev5 = 0x2086;
- u16 clip1loA_gaincode_rev6 = 0x2086;
- u16 clip1lo_gaincode;
- u8 crsminG_th = 0x18;
- u8 crsminG_th_rev5 = 0x18;
- u8 crsminG_th_rev6 = 0x18;
- u8 crsminA_th = 0x1e;
- u8 crsminA_th_rev4 = 0x24;
- u8 crsminA_th_rev5 = 0x24;
- u8 crsminA_th_rev6 = 0x24;
- u8 crsmin_th;
- u8 crsminlG_th = 0x18;
- u8 crsminlG_th_rev5 = 0x18;
- u8 crsminlG_th_rev6 = 0x18;
- u8 crsminlA_th = 0x1e;
- u8 crsminlA_th_rev4 = 0x24;
- u8 crsminlA_th_rev5 = 0x24;
- u8 crsminlA_th_rev6 = 0x24;
- u8 crsminl_th = 0;
- u8 crsminuG_th = 0x18;
- u8 crsminuG_th_rev5 = 0x18;
- u8 crsminuG_th_rev6 = 0x18;
- u8 crsminuA_th = 0x1e;
- u8 crsminuA_th_rev4 = 0x24;
- u8 crsminuA_th_rev5 = 0x24;
- u8 crsminuA_th_rev6 = 0x24;
- u8 crsminuA_th_rev6_224B0 = 0x2d;
- u8 crsminu_th;
- u16 nbclipG_th = 0x20d;
- u16 nbclipG_th_rev4 = 0x1a1;
- u16 nbclipG_th_rev5 = 0x1d0;
- u16 nbclipG_th_rev6 = 0x1d0;
- u16 nbclipA_th = 0x1a1;
- u16 nbclipA_th_rev4 = 0x107;
- u16 nbclipA_th_rev5 = 0x0a9;
- u16 nbclipA_th_rev6 = 0x0f0;
- u16 nbclip_th = 0;
- u8 w1clipG_th = 5;
- u8 w1clipG_th_rev5 = 9;
- u8 w1clipG_th_rev6 = 5;
- u8 w1clipA_th = 25, w1clip_th;
- u8 rssi_gain_default = 0x50;
- u8 rssiG_gain_rev6_224B0 = 0x50;
- u8 rssiA_gain_rev5 = 0x90;
- u8 rssiA_gain_rev6 = 0x90;
- u8 rssi_gain;
- u16 regval[21];
- u8 triso;
+ int j, type = 2;
+ u16 addr_offset = 0x2c5;
- triso = (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.triso :
- pi->srom_fem2g.triso;
+ for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++)
+ write_phy_reg(pi, addr_offset + j,
+ NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]);
+}
+
+static void wlc_phy_clip_det_nphy(struct brcms_phy *pi, u8 write, u16 *vals)
+{
+
+ if (write == 0) {
+ vals[0] = read_phy_reg(pi, 0x2c);
+ vals[1] = read_phy_reg(pi, 0x42);
+ } else {
+ write_phy_reg(pi, 0x2c, vals[0]);
+ write_phy_reg(pi, 0x42, vals[1]);
+ }
+}
+
+static void wlc_phy_ipa_internal_tssi_setup_nphy(struct brcms_phy *pi)
+{
+ u8 core;
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (pi->pubpi.radiorev == 5) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER, 0x5);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MUX, 0xe);
- wlc_phy_workarounds_nphy_gainctrl_2057_rev5(pi);
- } else if (pi->pubpi.radiorev == 7) {
- wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
+ if (pi->pubpi.radiorev != 5)
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIA, 0);
- mod_phy_reg(pi, 0x283, (0xff << 0), (0x44 << 0));
- mod_phy_reg(pi, 0x280, (0xff << 0), (0x44 << 0));
+ if (!NREV_IS(pi->pubpi.phy_rev, 7))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIG, 0x1);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX,
+ core, TSSIG, 0x31);
+ } else {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER, 0x9);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MUX, 0xc);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSIG, 0);
- } else if ((pi->pubpi.radiorev == 3)
- || (pi->pubpi.radiorev == 8)) {
- wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
+ if (pi->pubpi.radiorev != 5) {
+ if (!NREV_IS(pi->pubpi.phy_rev, 7))
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIA, 0x1);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TSSIA, 0x31);
+ }
+ }
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG,
+ 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC,
+ 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM,
+ 0x3);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1,
+ 0x0);
+ }
+ } else {
+ WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR31,
+ (CHSPEC_IS2G(pi->radio_chanspec)) ? 0x128 :
+ 0x80);
+ WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR30, 0x0);
+ WRITE_RADIO_SYN(pi, RADIO_2056, GPIO_MASTER1, 0x29);
- if (pi->pubpi.radiorev == 8) {
- mod_phy_reg(pi, 0x283,
- (0xff << 0), (0x44 << 0));
- mod_phy_reg(pi, 0x280,
- (0xff << 0), (0x44 << 0));
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_VCM_HG,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_IDAC,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_VCM,
+ 0x3);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TX_AMP_DET,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC1,
+ 0x8);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC2,
+ 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC3,
+ 0x0);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MASTER, 0x5);
+
+ if (pi->pubpi.radiorev != 5)
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX,
+ core, TSSIA, 0x0);
+ if (NREV_GE(pi->pubpi.phy_rev, 5))
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX,
+ core, TSSIG, 0x31);
+ else
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX,
+ core, TSSIG, 0x11);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MUX, 0xe);
+ } else {
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MASTER, 0x9);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TSSIA, 0x31);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TSSIG, 0x0);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ TX_SSI_MUX, 0xc);
}
- } else {
- wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi);
}
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ }
+}
- mod_phy_reg(pi, 0xa0, (0x1 << 6), (1 << 6));
+static void
+wlc_phy_rfctrl_override_nphy(struct brcms_phy *pi, u16 field, u16 value,
+ u8 core_mask, u8 off)
+{
+ u8 core_num;
+ u16 addr = 0, mask = 0, en_addr = 0, val_addr = 0, en_mask =
+ 0, val_mask = 0;
+ u8 shift = 0, val_shift = 0;
- mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
- mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
- currband =
- read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
- if (currband == 0) {
- if (NREV_GE(pi->pubpi.phy_rev, 6)) {
- if (pi->pubpi.radiorev == 11) {
- lna1_gain_db = lna1G_gain_db_rev6_224B0;
- lna2_gain_db = lna2G_gain_db_rev6_224B0;
- rfseq_init_gain =
- rfseqG_init_gain_rev6_224B0;
- init_gaincode =
- initG_gaincode_rev6_224B0;
- clip1hi_gaincode =
- clip1hiG_gaincode_rev6;
- clip1lo_gaincode =
- clip1loG_gaincode_rev6_224B0;
- nbclip_th = nbclipG_th_rev6;
- w1clip_th = w1clipG_th_rev6;
- crsmin_th = crsminG_th_rev6;
- crsminl_th = crsminlG_th_rev6;
- crsminu_th = crsminuG_th_rev6;
- rssi_gain = rssiG_gain_rev6_224B0;
- } else {
- lna1_gain_db = lna1G_gain_db_rev6;
- lna2_gain_db = lna2G_gain_db_rev6;
- if (pi->sh->boardflags & BFL_EXTLNA) {
+ en_mask = field;
+ for (core_num = 0; core_num < 2; core_num++) {
- rfseq_init_gain =
- rfseqG_init_gain_rev6_elna;
- init_gaincode =
- initG_gaincode_rev6_elna;
- } else {
- rfseq_init_gain =
- rfseqG_init_gain_rev6;
- init_gaincode =
- initG_gaincode_rev6;
- }
- clip1hi_gaincode =
- clip1hiG_gaincode_rev6;
- switch (triso) {
- case 0:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[0];
- break;
- case 1:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[1];
- break;
- case 2:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[2];
- break;
- case 3:
- default:
+ switch (field) {
+ case (0x1 << 1):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 2):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 1);
+ val_shift = 1;
+ break;
+ case (0x1 << 3):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 2);
+ val_shift = 2;
+ break;
+ case (0x1 << 4):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 4);
+ val_shift = 4;
+ break;
+ case (0x1 << 5):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 5);
+ val_shift = 5;
+ break;
+ case (0x1 << 6):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 7):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x1 << 7);
+ val_shift = 7;
+ break;
+ case (0x1 << 8):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x7 << 8);
+ val_shift = 8;
+ break;
+ case (0x1 << 11):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7a : 0x7d;
+ val_mask = (0x7 << 13);
+ val_shift = 13;
+ break;
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[3];
- break;
- case 4:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[4];
- break;
- case 5:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[5];
- break;
- case 6:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[6];
- break;
- case 7:
- clip1lo_gaincode =
- clip1loG_gaincode_rev6[7];
- break;
- }
- nbclip_th = nbclipG_th_rev6;
- w1clip_th = w1clipG_th_rev6;
- crsmin_th = crsminG_th_rev6;
- crsminl_th = crsminlG_th_rev6;
- crsminu_th = crsminuG_th_rev6;
- rssi_gain = rssi_gain_default;
- }
- } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
- lna1_gain_db = lna1G_gain_db_rev5;
- lna2_gain_db = lna2G_gain_db_rev5;
- if (pi->sh->boardflags & BFL_EXTLNA) {
+ case (0x1 << 9):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf8 : 0xfa;
+ val_mask = (0x7 << 0);
+ val_shift = 0;
+ break;
- rfseq_init_gain =
- rfseqG_init_gain_rev5_elna;
- init_gaincode =
- initG_gaincode_rev5_elna;
- } else {
- rfseq_init_gain = rfseqG_init_gain_rev5;
- init_gaincode = initG_gaincode_rev5;
- }
- clip1hi_gaincode = clip1hiG_gaincode_rev5;
- switch (triso) {
- case 0:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[0];
- break;
- case 1:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[1];
- break;
- case 2:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[2];
- break;
- case 3:
+ case (0x1 << 10):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf8 : 0xfa;
+ val_mask = (0x7 << 4);
+ val_shift = 4;
+ break;
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[3];
- break;
- case 4:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[4];
- break;
- case 5:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[5];
- break;
- case 6:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[6];
- break;
- case 7:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[7];
- break;
- default:
- clip1lo_gaincode =
- clip1loG_gaincode_rev5[3];
- break;
- }
- nbclip_th = nbclipG_th_rev5;
- w1clip_th = w1clipG_th_rev5;
- crsmin_th = crsminG_th_rev5;
- crsminl_th = crsminlG_th_rev5;
- crsminu_th = crsminuG_th_rev5;
- rssi_gain = rssi_gain_default;
- } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
- lna1_gain_db = lna1G_gain_db_rev4;
- lna2_gain_db = lna2G_gain_db;
- rfseq_init_gain = rfseqG_init_gain_rev4;
- init_gaincode = initG_gaincode_rev4;
- clip1hi_gaincode = clip1hiG_gaincode_rev4;
- clip1lo_gaincode = clip1loG_gaincode;
- nbclip_th = nbclipG_th_rev4;
- w1clip_th = w1clipG_th;
- crsmin_th = crsminG_th;
- crsminl_th = crsminlG_th;
- crsminu_th = crsminuG_th;
- rssi_gain = rssi_gain_default;
- } else {
- lna1_gain_db = lna1G_gain_db;
- lna2_gain_db = lna2G_gain_db;
- rfseq_init_gain = rfseqG_init_gain;
- init_gaincode = initG_gaincode;
- clip1hi_gaincode = clip1hiG_gaincode;
- clip1lo_gaincode = clip1loG_gaincode;
- nbclip_th = nbclipG_th;
- w1clip_th = w1clipG_th;
- crsmin_th = crsminG_th;
- crsminl_th = crsminlG_th;
- crsminu_th = crsminuG_th;
- rssi_gain = rssi_gain_default;
+ case (0x1 << 12):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7b : 0x7e;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 13):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0x7c : 0x7f;
+ val_mask = (0xffff << 0);
+ val_shift = 0;
+ break;
+ case (0x1 << 14):
+ en_addr = (core_num == 0) ? 0xe7 : 0xec;
+ val_addr = (core_num == 0) ? 0xf9 : 0xfb;
+ val_mask = (0x3 << 6);
+ val_shift = 6;
+ break;
+ case (0x1 << 0):
+ en_addr = (core_num == 0) ? 0xe5 : 0xe6;
+ val_addr = (core_num == 0) ? 0xf9 : 0xfb;
+ val_mask = (0x1 << 15);
+ val_shift = 15;
+ break;
+ default:
+ addr = 0xffff;
+ break;
}
- tia_gain_db = tiaG_gain_db;
- tia_gainbits = tiaG_gainbits;
- clip1md_gaincode = clip1mdG_gaincode;
- } else {
- if (NREV_GE(pi->pubpi.phy_rev, 6)) {
- lna1_gain_db = lna1A_gain_db_rev6;
- lna2_gain_db = lna2A_gain_db_rev6;
- tia_gain_db = tiaA_gain_db_rev6;
- tia_gainbits = tiaA_gainbits_rev6;
- rfseq_init_gain = rfseqA_init_gain_rev6;
- init_gaincode = initA_gaincode_rev6;
- clip1hi_gaincode = clip1hiA_gaincode_rev6;
- clip1md_gaincode = clip1mdA_gaincode_rev6;
- clip1lo_gaincode = clip1loA_gaincode_rev6;
- crsmin_th = crsminA_th_rev6;
- crsminl_th = crsminlA_th_rev6;
- if ((pi->pubpi.radiorev == 11) &&
- (CHSPEC_IS40(pi->radio_chanspec) == 0)) {
- crsminu_th = crsminuA_th_rev6_224B0;
- } else {
- crsminu_th = crsminuA_th_rev6;
- }
- nbclip_th = nbclipA_th_rev6;
- rssi_gain = rssiA_gain_rev6;
- } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
- lna1_gain_db = lna1A_gain_db_rev5;
- lna2_gain_db = lna2A_gain_db_rev5;
- tia_gain_db = tiaA_gain_db_rev5;
- tia_gainbits = tiaA_gainbits_rev5;
- rfseq_init_gain = rfseqA_init_gain_rev5;
- init_gaincode = initA_gaincode_rev5;
- clip1hi_gaincode = clip1hiA_gaincode_rev5;
- clip1md_gaincode = clip1mdA_gaincode_rev5;
- clip1lo_gaincode = clip1loA_gaincode_rev5;
- crsmin_th = crsminA_th_rev5;
- crsminl_th = crsminlA_th_rev5;
- crsminu_th = crsminuA_th_rev5;
- nbclip_th = nbclipA_th_rev5;
- rssi_gain = rssiA_gain_rev5;
- } else if (NREV_IS(pi->pubpi.phy_rev, 4)) {
- lna1_gain_db = lna1A_gain_db_rev4;
- lna2_gain_db = lna2A_gain_db_rev4;
- tia_gain_db = tiaA_gain_db_rev4;
- tia_gainbits = tiaA_gainbits_rev4;
- if (pi->sh->boardflags & BFL_EXTLNA_5GHz) {
- rfseq_init_gain =
- rfseqA_init_gain_rev4_elna;
- init_gaincode =
- initA_gaincode_rev4_elna;
- } else {
- rfseq_init_gain = rfseqA_init_gain_rev4;
- init_gaincode = initA_gaincode_rev4;
- }
- clip1hi_gaincode = clip1hiA_gaincode_rev4;
- clip1md_gaincode = clip1mdA_gaincode_rev4;
- clip1lo_gaincode = clip1loA_gaincode_rev4;
- crsmin_th = crsminA_th_rev4;
- crsminl_th = crsminlA_th_rev4;
- crsminu_th = crsminuA_th_rev4;
- nbclip_th = nbclipA_th_rev4;
- rssi_gain = rssi_gain_default;
+ if (off) {
+ and_phy_reg(pi, en_addr, ~en_mask);
+ and_phy_reg(pi, val_addr, ~val_mask);
} else {
- lna1_gain_db = lna1A_gain_db;
- lna2_gain_db = lna2A_gain_db;
- tia_gain_db = tiaA_gain_db;
- tia_gainbits = tiaA_gainbits;
- rfseq_init_gain = rfseqA_init_gain;
- init_gaincode = initA_gaincode;
- clip1hi_gaincode = clip1hiA_gaincode;
- clip1md_gaincode = clip1mdA_gaincode;
- clip1lo_gaincode = clip1loA_gaincode;
- crsmin_th = crsminA_th;
- crsminl_th = crsminlA_th;
- crsminu_th = crsminuA_th;
- nbclip_th = nbclipA_th;
- rssi_gain = rssi_gain_default;
+
+ if ((core_mask == 0)
+ || (core_mask & (1 << core_num))) {
+ or_phy_reg(pi, en_addr, en_mask);
+
+ if (addr != 0xffff)
+ mod_phy_reg(pi, val_addr,
+ val_mask,
+ (value <<
+ val_shift));
+ }
}
- w1clip_th = w1clipA_th;
}
+ } else {
- write_radio_reg(pi,
- (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC |
- RADIO_2056_RX0), 0x17);
- write_radio_reg(pi,
- (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC |
- RADIO_2056_RX1), 0x17);
+ if (off) {
+ and_phy_reg(pi, 0xec, ~field);
+ value = 0x0;
+ } else {
+ or_phy_reg(pi, 0xec, field);
+ }
- write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX0),
- 0xf0);
- write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX1),
- 0xf0);
+ for (core_num = 0; core_num < 2; core_num++) {
- write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX0),
- 0x0);
- write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX1),
- 0x0);
+ switch (field) {
+ case (0x1 << 1):
+ case (0x1 << 9):
+ case (0x1 << 12):
+ case (0x1 << 13):
+ case (0x1 << 14):
+ addr = 0x78;
- write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX0),
- rssi_gain);
- write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX1),
- rssi_gain);
+ core_mask = 0x1;
+ break;
+ case (0x1 << 2):
+ case (0x1 << 3):
+ case (0x1 << 4):
+ case (0x1 << 5):
+ case (0x1 << 6):
+ case (0x1 << 7):
+ case (0x1 << 8):
+ addr = (core_num == 0) ? 0x7a : 0x7d;
+ break;
+ case (0x1 << 10):
+ addr = (core_num == 0) ? 0x7b : 0x7e;
+ break;
+ case (0x1 << 11):
+ addr = (core_num == 0) ? 0x7c : 0x7f;
+ break;
+ default:
+ addr = 0xffff;
+ }
- write_radio_reg(pi,
- (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC |
- RADIO_2056_RX0), 0x17);
- write_radio_reg(pi,
- (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC |
- RADIO_2056_RX1), 0x17);
+ switch (field) {
+ case (0x1 << 1):
+ mask = (0x7 << 3);
+ shift = 3;
+ break;
+ case (0x1 << 9):
+ mask = (0x1 << 2);
+ shift = 2;
+ break;
+ case (0x1 << 12):
+ mask = (0x1 << 8);
+ shift = 8;
+ break;
+ case (0x1 << 13):
+ mask = (0x1 << 9);
+ shift = 9;
+ break;
+ case (0x1 << 14):
+ mask = (0xf << 12);
+ shift = 12;
+ break;
+ case (0x1 << 2):
+ mask = (0x1 << 0);
+ shift = 0;
+ break;
+ case (0x1 << 3):
+ mask = (0x1 << 1);
+ shift = 1;
+ break;
+ case (0x1 << 4):
+ mask = (0x1 << 2);
+ shift = 2;
+ break;
+ case (0x1 << 5):
+ mask = (0x3 << 4);
+ shift = 4;
+ break;
+ case (0x1 << 6):
+ mask = (0x3 << 6);
+ shift = 6;
+ break;
+ case (0x1 << 7):
+ mask = (0x1 << 8);
+ shift = 8;
+ break;
+ case (0x1 << 8):
+ mask = (0x1 << 9);
+ shift = 9;
+ break;
+ case (0x1 << 10):
+ mask = 0x1fff;
+ shift = 0x0;
+ break;
+ case (0x1 << 11):
+ mask = 0x1fff;
+ shift = 0x0;
+ break;
+ default:
+ mask = 0x0;
+ shift = 0x0;
+ break;
+ }
- write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX0),
- 0xFF);
- write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX1),
- 0xFF);
+ if ((addr != 0xffff) && (core_mask & (1 << core_num)))
+ mod_phy_reg(pi, addr, mask, (value << shift));
+ }
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8,
- 8, lna1_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8,
- 8, lna1_gain_db);
+ or_phy_reg(pi, 0xec, (0x1 << 0));
+ or_phy_reg(pi, 0x78, (0x1 << 0));
+ udelay(1);
+ and_phy_reg(pi, 0xec, ~(0x1 << 0));
+ }
+}
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10,
- 8, lna2_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10,
- 8, lna2_gain_db);
+static void wlc_phy_txpwrctrl_idle_tssi_nphy(struct brcms_phy *pi)
+{
+ s32 rssi_buf[4];
+ s32 int_val;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20,
- 8, tia_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20,
- 8, tia_gain_db);
+ if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) || PHY_MUTED(pi))
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20,
- 8, tia_gainbits);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20,
- 8, tia_gainbits);
+ return;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 6, 0x40,
- 8, &lpf_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 6, 0x40,
- 8, &lpf_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 6, 0x40,
- 8, &lpf_gainbits);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 6, 0x40,
- 8, &lpf_gainbits);
+ if (PHY_IPA(pi))
+ wlc_phy_ipa_internal_tssi_setup_nphy(pi);
- write_phy_reg(pi, 0x20, init_gaincode);
- write_phy_reg(pi, 0x2a7, init_gaincode);
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
+ 0, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 0);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- pi->pubpi.phy_corenum, 0x106, 16,
- rfseq_init_gain);
+ wlc_phy_stopplayback_nphy(pi);
- write_phy_reg(pi, 0x22, clip1hi_gaincode);
- write_phy_reg(pi, 0x2a9, clip1hi_gaincode);
+ wlc_phy_tx_tone_nphy(pi, 4000, 0, 0, 0, false);
- write_phy_reg(pi, 0x24, clip1md_gaincode);
- write_phy_reg(pi, 0x2ab, clip1md_gaincode);
+ udelay(20);
+ int_val =
+ wlc_phy_poll_rssi_nphy(pi, (u8) NPHY_RSSI_SEL_TSSI_2G, rssi_buf,
+ 1);
+ wlc_phy_stopplayback_nphy(pi);
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, 0);
- write_phy_reg(pi, 0x37, clip1lo_gaincode);
- write_phy_reg(pi, 0x2ad, clip1lo_gaincode);
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
+ 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 1);
- mod_phy_reg(pi, 0x27d, (0xff << 0), (crsmin_th << 0));
- mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0));
- mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0));
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- write_phy_reg(pi, 0x2b, nbclip_th);
- write_phy_reg(pi, 0x41, nbclip_th);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g =
+ (u8) ((int_val >> 24) & 0xff);
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g =
+ (u8) ((int_val >> 24) & 0xff);
- mod_phy_reg(pi, 0x27, (0x3f << 0), (w1clip_th << 0));
- mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1clip_th << 0));
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g =
+ (u8) ((int_val >> 8) & 0xff);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g =
+ (u8) ((int_val >> 8) & 0xff);
+ } else {
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g =
+ (u8) ((int_val >> 24) & 0xff);
- write_phy_reg(pi, 0x150, 0x809c);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g =
+ (u8) ((int_val >> 8) & 0xff);
- } else {
+ pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g =
+ (u8) ((int_val >> 16) & 0xff);
+ pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g =
+ (u8) ((int_val) & 0xff);
+ }
- mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
- mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+}
- write_phy_reg(pi, 0x2b, 0x84);
- write_phy_reg(pi, 0x41, 0x84);
+static void wlc_phy_txpwr_limit_to_tbl_nphy(struct brcms_phy *pi)
+{
+ u8 idx, idx2, i, delta_ind;
- if (CHSPEC_IS20(pi->radio_chanspec)) {
- write_phy_reg(pi, 0x6b, 0x2b);
- write_phy_reg(pi, 0x6c, 0x2b);
- write_phy_reg(pi, 0x6d, 0x9);
- write_phy_reg(pi, 0x6e, 0x9);
- }
+ for (idx = TXP_FIRST_CCK; idx <= TXP_LAST_CCK; idx++)
+ pi->adj_pwr_tbl_nphy[idx] = pi->tx_power_offset[idx];
- w1th = NPHY_RSSICAL_W1_TARGET - 4;
- mod_phy_reg(pi, 0x27, (0x3f << 0), (w1th << 0));
- mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1th << 0));
+ for (i = 0; i < 4; i++) {
+ idx2 = 0;
- if (CHSPEC_IS20(pi->radio_chanspec)) {
- mod_phy_reg(pi, 0x1c, (0x1f << 0), (0x1 << 0));
- mod_phy_reg(pi, 0x32, (0x1f << 0), (0x1 << 0));
+ delta_ind = 0;
- mod_phy_reg(pi, 0x1d, (0x1f << 0), (0x1 << 0));
- mod_phy_reg(pi, 0x33, (0x1f << 0), (0x1 << 0));
- }
+ switch (i) {
+ case 0:
- write_phy_reg(pi, 0x150, 0x809c);
+ if (CHSPEC_IS40(pi->radio_chanspec)
+ && NPHY_IS_SROM_REINTERPRET) {
+ idx = TXP_FIRST_MCS_40_SISO;
+ } else {
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_OFDM_40_SISO : TXP_FIRST_OFDM;
+ delta_ind = 1;
+ }
+ break;
- if (pi->nphy_gain_boost)
- if ((CHSPEC_IS2G(pi->radio_chanspec)) &&
- (CHSPEC_IS40(pi->radio_chanspec)))
- hpf_code = 4;
- else
- hpf_code = 5;
- else if (CHSPEC_IS40(pi->radio_chanspec))
- hpf_code = 6;
- else
- hpf_code = 7;
+ case 1:
- mod_phy_reg(pi, 0x20, (0x1f << 7), (hpf_code << 7));
- mod_phy_reg(pi, 0x36, (0x1f << 7), (hpf_code << 7));
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_MCS_40_CDD : TXP_FIRST_MCS_20_CDD;
+ break;
- for (ctr = 0; ctr < 4; ctr++) {
- regval[ctr] = (hpf_code << 8) | 0x7c;
- }
- wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval);
+ case 2:
- wlc_phy_adjust_lnagaintbl_nphy(pi);
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_MCS_40_STBC : TXP_FIRST_MCS_20_STBC;
+ break;
- if (pi->nphy_elna_gain_config) {
- regval[0] = 0;
- regval[1] = 1;
- regval[2] = 1;
- regval[3] = 1;
- wlc_phy_table_write_nphy(pi, 2, 4, 8, 16, regval);
- wlc_phy_table_write_nphy(pi, 3, 4, 8, 16, regval);
+ case 3:
- for (ctr = 0; ctr < 4; ctr++) {
- regval[ctr] = (hpf_code << 8) | 0x74;
- }
- wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval);
+ idx = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ TXP_FIRST_MCS_40_SDM : TXP_FIRST_MCS_20_SDM;
+ break;
}
- if (NREV_IS(pi->pubpi.phy_rev, 2)) {
- for (ctr = 0; ctr < 21; ctr++) {
- regval[ctr] = 3 * ctr;
- }
- wlc_phy_table_write_nphy(pi, 0, 21, 32, 16, regval);
- wlc_phy_table_write_nphy(pi, 1, 21, 32, 16, regval);
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ idx = idx + delta_ind;
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
- for (ctr = 0; ctr < 21; ctr++) {
- regval[ctr] = (u16) ctr;
- }
- wlc_phy_table_write_nphy(pi, 2, 21, 32, 16, regval);
- wlc_phy_table_write_nphy(pi, 3, 21, 32, 16, regval);
- }
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
- wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_UPDATEGAINU,
- rfseq_updategainu_events,
- rfseq_updategainu_dlys,
- sizeof(rfseq_updategainu_events) /
- sizeof(rfseq_updategainu_events[0]));
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
- mod_phy_reg(pi, 0x153, (0xff << 8), (90 << 8));
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx++];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ idx = idx + 1 - delta_ind;
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
- if (CHSPEC_IS2G(pi->radio_chanspec))
- mod_phy_reg(pi,
- (NPHY_TO_BPHY_OFF + BPHY_OPTIONAL_MODES),
- 0x7f, 0x4);
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
+ pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] =
+ pi->tx_power_offset[idx];
}
}
-static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi)
+static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
{
- s8 lna1_gain_db[] = { 8, 13, 17, 22 };
- s8 lna2_gain_db[] = { -2, 7, 11, 15 };
- s8 tia_gain_db[] = { -4, -1, 2, 5, 5, 5, 5, 5, 5, 5 };
- s8 tia_gainbits[] = {
- 0x0, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 };
+ u32 idx;
+ s16 a1[2], b0[2], b1[2];
+ s8 target_pwr_qtrdbm[2];
+ s32 num, den, pwr_est;
+ u8 chan_freq_range;
+ u8 idle_tssi[2];
+ u32 tbl_id, tbl_len, tbl_offset;
+ u32 regval[64];
+ u8 core;
- mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
- mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
+ (void)R_REG(&pi->regs->maccontrol);
+ udelay(1);
+ }
- mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0));
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
- mod_phy_reg(pi, 0x283, (0xff << 0), (0x3c << 0));
- mod_phy_reg(pi, 0x280, (0xff << 0), (0x3c << 0));
+ or_phy_reg(pi, 0x122, (0x1 << 0));
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x8, 8,
- lna1_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x8, 8,
- lna1_gain_db);
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ and_phy_reg(pi, 0x1e7, (u16) (~(0x1 << 15)));
+ else
+ or_phy_reg(pi, 0x1e7, (0x1 << 15));
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, 8,
- lna2_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, 8,
- lna2_gain_db);
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8,
- tia_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8,
- tia_gain_db);
+ if (pi->sh->sromrev < 4) {
+ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
+ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
+ target_pwr_qtrdbm[0] = 13 * 4;
+ target_pwr_qtrdbm[1] = 13 * 4;
+ a1[0] = -424;
+ a1[1] = -424;
+ b0[0] = 5612;
+ b0[1] = 5612;
+ b1[1] = -1393;
+ b1[0] = -1393;
+ } else {
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8,
- tia_gainbits);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8,
- tia_gainbits);
+ chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
+ switch (chan_freq_range) {
+ case WL_CHAN_FREQ_RANGE_2G:
+ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
+ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
+ target_pwr_qtrdbm[0] =
+ pi->nphy_pwrctrl_info[0].max_pwr_2g;
+ target_pwr_qtrdbm[1] =
+ pi->nphy_pwrctrl_info[1].max_pwr_2g;
+ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1;
+ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1;
+ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b1;
+ break;
+ case WL_CHAN_FREQ_RANGE_5GL:
+ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
+ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
+ target_pwr_qtrdbm[0] =
+ pi->nphy_pwrctrl_info[0].max_pwr_5gl;
+ target_pwr_qtrdbm[1] =
+ pi->nphy_pwrctrl_info[1].max_pwr_5gl;
+ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1;
+ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1;
+ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1;
+ break;
+ case WL_CHAN_FREQ_RANGE_5GM:
+ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
+ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
+ target_pwr_qtrdbm[0] =
+ pi->nphy_pwrctrl_info[0].max_pwr_5gm;
+ target_pwr_qtrdbm[1] =
+ pi->nphy_pwrctrl_info[1].max_pwr_5gm;
+ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1;
+ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1;
+ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b1;
+ break;
+ case WL_CHAN_FREQ_RANGE_5GH:
+ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
+ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
+ target_pwr_qtrdbm[0] =
+ pi->nphy_pwrctrl_info[0].max_pwr_5gh;
+ target_pwr_qtrdbm[1] =
+ pi->nphy_pwrctrl_info[1].max_pwr_5gh;
+ a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1;
+ a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1;
+ b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0;
+ b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0;
+ b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1;
+ b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1;
+ break;
+ default:
+ idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
+ idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
+ target_pwr_qtrdbm[0] = 13 * 4;
+ target_pwr_qtrdbm[1] = 13 * 4;
+ a1[0] = -424;
+ a1[1] = -424;
+ b0[0] = 5612;
+ b0[1] = 5612;
+ b1[1] = -1393;
+ b1[0] = -1393;
+ break;
+ }
+ }
- write_phy_reg(pi, 0x37, 0x74);
- write_phy_reg(pi, 0x2ad, 0x74);
- write_phy_reg(pi, 0x38, 0x18);
- write_phy_reg(pi, 0x2ae, 0x18);
+ target_pwr_qtrdbm[0] = (s8) pi->tx_power_max;
+ target_pwr_qtrdbm[1] = (s8) pi->tx_power_max;
- write_phy_reg(pi, 0x2b, 0xe8);
- write_phy_reg(pi, 0x41, 0xe8);
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->srom_fem2g.tssipos)
+ or_phy_reg(pi, 0x1e9, (0x1 << 14));
- if (CHSPEC_IS20(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (core = 0; core <= 1; core++) {
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TX_SSI_MUX,
+ 0xe);
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057,
+ TX, core,
+ TX_SSI_MUX,
+ 0xc);
+ }
+ }
+ } else {
+ if (PHY_IPA(pi)) {
- mod_phy_reg(pi, 0x300, (0x3f << 0), (0x12 << 0));
- mod_phy_reg(pi, 0x301, (0x3f << 0), (0x12 << 0));
- } else {
+ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX0,
+ (CHSPEC_IS5G
+ (pi->radio_chanspec)) ?
+ 0xc : 0xe);
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX1,
+ (CHSPEC_IS5G
+ (pi->radio_chanspec)) ?
+ 0xc : 0xe);
+ } else {
- mod_phy_reg(pi, 0x300, (0x3f << 0), (0x10 << 0));
- mod_phy_reg(pi, 0x301, (0x3f << 0), (0x10 << 0));
+ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX0, 0x11);
+ write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
+ RADIO_2056_TX1, 0x11);
+ }
+ }
}
-}
-static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi)
-{
- u16 currband;
- s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 };
- s8 *lna1_gain_db = NULL;
- s8 *lna1_gain_db_2 = NULL;
- s8 *lna2_gain_db = NULL;
- s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 };
- s8 *tia_gain_db;
- s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 };
- s8 *tia_gainbits;
- u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f };
- u16 *rfseq_init_gain;
- u16 init_gaincode;
- u16 clip1hi_gaincode;
- u16 clip1md_gaincode = 0;
- u16 clip1md_gaincode_B;
- u16 clip1lo_gaincode;
- u16 clip1lo_gaincode_B;
- u8 crsminl_th = 0;
- u8 crsminu_th;
- u16 nbclip_th = 0;
- u8 w1clip_th;
- u16 freq;
- s8 nvar_baseline_offset0 = 0, nvar_baseline_offset1 = 0;
- u8 chg_nbclip_th = 0;
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
+ (void)R_REG(&pi->regs->maccontrol);
+ udelay(1);
+ }
- mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13));
- mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13));
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0));
+ else
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0));
- currband = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand;
- if (currband == 0) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ mod_phy_reg(pi, 0x222, (0xff << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0));
+ else if (NREV_GT(pi->pubpi.phy_rev, 1))
+ mod_phy_reg(pi, 0x222, (0xff << 0),
+ (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0));
- lna1_gain_db = lna1G_gain_db_rev7;
+ if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
+ wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8,
- lna1_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8,
- lna1_gain_db);
+ write_phy_reg(pi, 0x1e8, (0x3 << 8) | (240 << 0));
- mod_phy_reg(pi, 0x283, (0xff << 0), (0x40 << 0));
+ write_phy_reg(pi, 0x1e9,
+ (1 << 15) | (idle_tssi[0] << 0) | (idle_tssi[1] << 8));
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- mod_phy_reg(pi, 0x280, (0xff << 0), (0x3e << 0));
- mod_phy_reg(pi, 0x283, (0xff << 0), (0x3e << 0));
+ write_phy_reg(pi, 0x1ea,
+ (target_pwr_qtrdbm[0] << 0) |
+ (target_pwr_qtrdbm[1] << 8));
+
+ tbl_len = 64;
+ tbl_offset = 0;
+ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
+ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
+
+ for (idx = 0; idx < tbl_len; idx++) {
+ num = 8 *
+ (16 * b0[tbl_id - 26] + b1[tbl_id - 26] * idx);
+ den = 32768 + a1[tbl_id - 26] * idx;
+ pwr_est = max(((4 * num + den / 2) / den), -8);
+ if (NREV_LT(pi->pubpi.phy_rev, 3)) {
+ if (idx <=
+ (uint) (31 - idle_tssi[tbl_id - 26] + 1))
+ pwr_est =
+ max(pwr_est,
+ target_pwr_qtrdbm
+ [tbl_id - 26] + 1);
+ }
+ regval[idx] = (u32) pwr_est;
}
+ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
+ regval);
+ }
- mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0));
+ wlc_phy_txpwr_limit_to_tbl_nphy(pi);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, 8,
+ pi->adj_pwr_tbl_nphy);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, 8,
+ pi->adj_pwr_tbl_nphy);
- if (CHSPEC_IS20(pi->radio_chanspec)) {
- mod_phy_reg(pi, 0x300, (0x3f << 0), (13 << 0));
- mod_phy_reg(pi, 0x301, (0x3f << 0), (13 << 0));
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi)
+{
+ u32 *tx_pwrctrl_tbl = NULL;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev4n6;
+ else if (pi->pubpi.radiorev == 3)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev3;
+ else if (pi->pubpi.radiorev == 5)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev5;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_2g_2057rev7;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5;
+ } else {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa;
}
} else {
- init_gaincode = 0x9e;
- clip1hi_gaincode = 0x9e;
- clip1md_gaincode_B = 0x24;
- clip1lo_gaincode = 0x8a;
- clip1lo_gaincode_B = 8;
- rfseq_init_gain = rfseqA_init_gain_rev7;
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g_2057;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_ipa_5g_2057rev7;
+ } else {
+ tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g;
+ }
+ }
- tia_gain_db = tiaA_gain_db_rev7;
- tia_gainbits = tiaA_gainbits_rev7;
+ return tx_pwrctrl_tbl;
+}
- freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec));
- if (CHSPEC_IS20(pi->radio_chanspec)) {
+static void wlc_phy_restore_rssical_nphy(struct brcms_phy *pi)
+{
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->nphy_rssical_chanspec_2G == 0)
+ return;
- w1clip_th = 25;
- clip1md_gaincode = 0x82;
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[0]);
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[1]);
+ } else {
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[0]);
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_2G[1]);
+ }
- if ((freq <= 5080) || (freq == 5825)) {
+ write_phy_reg(pi, 0x1a6,
+ pi->rssical_cache.rssical_phyregs_2G[0]);
+ write_phy_reg(pi, 0x1ac,
+ pi->rssical_cache.rssical_phyregs_2G[1]);
+ write_phy_reg(pi, 0x1b2,
+ pi->rssical_cache.rssical_phyregs_2G[2]);
+ write_phy_reg(pi, 0x1b8,
+ pi->rssical_cache.rssical_phyregs_2G[3]);
+ write_phy_reg(pi, 0x1a4,
+ pi->rssical_cache.rssical_phyregs_2G[4]);
+ write_phy_reg(pi, 0x1aa,
+ pi->rssical_cache.rssical_phyregs_2G[5]);
+ write_phy_reg(pi, 0x1b0,
+ pi->rssical_cache.rssical_phyregs_2G[6]);
+ write_phy_reg(pi, 0x1b6,
+ pi->rssical_cache.rssical_phyregs_2G[7]);
+ write_phy_reg(pi, 0x1a5,
+ pi->rssical_cache.rssical_phyregs_2G[8]);
+ write_phy_reg(pi, 0x1ab,
+ pi->rssical_cache.rssical_phyregs_2G[9]);
+ write_phy_reg(pi, 0x1b1,
+ pi->rssical_cache.rssical_phyregs_2G[10]);
+ write_phy_reg(pi, 0x1b7,
+ pi->rssical_cache.rssical_phyregs_2G[11]);
- s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 };
- s8 lna1A_gain_db_2_rev7[] = {
- 11, 17, 22, 25 };
- s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+ } else {
+ if (pi->nphy_rssical_chanspec_5G == 0)
+ return;
- crsminu_th = 0x3e;
- lna1_gain_db = lna1A_gain_db_rev7;
- lna1_gain_db_2 = lna1A_gain_db_2_rev7;
- lna2_gain_db = lna2A_gain_db_rev7;
- } else if ((freq >= 5500) && (freq <= 5700)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[0]);
+ mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1,
+ RADIO_2057_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[1]);
+ } else {
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[0]);
+ mod_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1,
+ RADIO_2056_VCM_MASK,
+ pi->rssical_cache.
+ rssical_radio_regs_5G[1]);
+ }
- s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 };
- s8 lna1A_gain_db_2_rev7[] = {
- 12, 18, 22, 26 };
- s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 };
+ write_phy_reg(pi, 0x1a6,
+ pi->rssical_cache.rssical_phyregs_5G[0]);
+ write_phy_reg(pi, 0x1ac,
+ pi->rssical_cache.rssical_phyregs_5G[1]);
+ write_phy_reg(pi, 0x1b2,
+ pi->rssical_cache.rssical_phyregs_5G[2]);
+ write_phy_reg(pi, 0x1b8,
+ pi->rssical_cache.rssical_phyregs_5G[3]);
+ write_phy_reg(pi, 0x1a4,
+ pi->rssical_cache.rssical_phyregs_5G[4]);
+ write_phy_reg(pi, 0x1aa,
+ pi->rssical_cache.rssical_phyregs_5G[5]);
+ write_phy_reg(pi, 0x1b0,
+ pi->rssical_cache.rssical_phyregs_5G[6]);
+ write_phy_reg(pi, 0x1b6,
+ pi->rssical_cache.rssical_phyregs_5G[7]);
+ write_phy_reg(pi, 0x1a5,
+ pi->rssical_cache.rssical_phyregs_5G[8]);
+ write_phy_reg(pi, 0x1ab,
+ pi->rssical_cache.rssical_phyregs_5G[9]);
+ write_phy_reg(pi, 0x1b1,
+ pi->rssical_cache.rssical_phyregs_5G[10]);
+ write_phy_reg(pi, 0x1b7,
+ pi->rssical_cache.rssical_phyregs_5G[11]);
+ }
+}
- crsminu_th = 0x45;
- clip1md_gaincode_B = 0x14;
- nbclip_th = 0xff;
- chg_nbclip_th = 1;
- lna1_gain_db = lna1A_gain_db_rev7;
- lna1_gain_db_2 = lna1A_gain_db_2_rev7;
- lna2_gain_db = lna2A_gain_db_rev7;
+static void wlc_phy_internal_cal_txgain_nphy(struct brcms_phy *pi)
+{
+ u16 txcal_gain[2];
+
+ pi->nphy_txcal_pwr_idx[0] = pi->nphy_cal_orig_pwr_idx[0];
+ pi->nphy_txcal_pwr_idx[1] = pi->nphy_cal_orig_pwr_idx[0];
+ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true);
+ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true);
+
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ txcal_gain);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F40;
+ txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F40;
+ } else {
+ txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F60;
+ txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F60;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
+ txcal_gain);
+}
+
+static void wlc_phy_precal_txgain_nphy(struct brcms_phy *pi)
+{
+ bool save_bbmult = false;
+ u8 txcal_index_2057_rev5n7 = 0;
+ u8 txcal_index_2057_rev3n4n6 = 10;
+
+ if (pi->use_int_tx_iqlo_cal_nphy) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6)) {
+
+ pi->nphy_txcal_pwr_idx[0] =
+ txcal_index_2057_rev3n4n6;
+ pi->nphy_txcal_pwr_idx[1] =
+ txcal_index_2057_rev3n4n6;
+ wlc_phy_txpwr_index_nphy(
+ pi, 3,
+ txcal_index_2057_rev3n4n6,
+ false);
} else {
- s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 };
- s8 lna1A_gain_db_2_rev7[] = {
- 12, 18, 22, 26 };
- s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 };
+ pi->nphy_txcal_pwr_idx[0] =
+ txcal_index_2057_rev5n7;
+ pi->nphy_txcal_pwr_idx[1] =
+ txcal_index_2057_rev5n7;
+ wlc_phy_txpwr_index_nphy(
+ pi, 3,
+ txcal_index_2057_rev5n7,
+ false);
+ }
+ save_bbmult = true;
- crsminu_th = 0x41;
- lna1_gain_db = lna1A_gain_db_rev7;
- lna1_gain_db_2 = lna1A_gain_db_2_rev7;
- lna2_gain_db = lna2A_gain_db_rev7;
+ } else if (NREV_LT(pi->pubpi.phy_rev, 5)) {
+ wlc_phy_cal_txgainctrl_nphy(pi, 11, false);
+ if (pi->sh->hw_phytxchain != 3) {
+ pi->nphy_txcal_pwr_idx[1] =
+ pi->nphy_txcal_pwr_idx[0];
+ wlc_phy_txpwr_index_nphy(pi, 3,
+ pi->
+ nphy_txcal_pwr_idx[0],
+ true);
+ save_bbmult = true;
}
- if (freq <= 4920) {
- nvar_baseline_offset0 = 5;
- nvar_baseline_offset1 = 5;
- } else if ((freq > 4920) && (freq <= 5320)) {
- nvar_baseline_offset0 = 3;
- nvar_baseline_offset1 = 5;
- } else if ((freq > 5320) && (freq <= 5700)) {
- nvar_baseline_offset0 = 3;
- nvar_baseline_offset1 = 2;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ wlc_phy_cal_txgainctrl_nphy(pi, 12,
+ false);
+ } else {
+ pi->nphy_txcal_pwr_idx[0] = 80;
+ pi->nphy_txcal_pwr_idx[1] = 80;
+ wlc_phy_txpwr_index_nphy(pi, 3, 80,
+ false);
+ save_bbmult = true;
+ }
} else {
- nvar_baseline_offset0 = 4;
- nvar_baseline_offset1 = 0;
+ wlc_phy_internal_cal_txgain_nphy(pi);
+ save_bbmult = true;
}
- } else {
-
- crsminu_th = 0x3a;
- crsminl_th = 0x3a;
- w1clip_th = 20;
- if ((freq >= 4920) && (freq <= 5320)) {
- nvar_baseline_offset0 = 4;
- nvar_baseline_offset1 = 5;
- } else if ((freq > 5320) && (freq <= 5550)) {
- nvar_baseline_offset0 = 4;
- nvar_baseline_offset1 = 2;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ wlc_phy_cal_txgainctrl_nphy(pi, 12,
+ false);
+ else
+ wlc_phy_cal_txgainctrl_nphy(pi, 14,
+ false);
} else {
- nvar_baseline_offset0 = 5;
- nvar_baseline_offset1 = 3;
+ wlc_phy_internal_cal_txgain_nphy(pi);
+ save_bbmult = true;
}
}
- write_phy_reg(pi, 0x20, init_gaincode);
- write_phy_reg(pi, 0x2a7, init_gaincode);
+ } else {
+ wlc_phy_cal_txgainctrl_nphy(pi, 10, false);
+ }
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
- pi->pubpi.phy_corenum, 0x106, 16,
- rfseq_init_gain);
+ if (save_bbmult)
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16,
+ &pi->nphy_txcal_bbmult);
+}
- write_phy_reg(pi, 0x22, clip1hi_gaincode);
- write_phy_reg(pi, 0x2a9, clip1hi_gaincode);
+static void
+wlc_phy_rfctrlintc_override_nphy(struct brcms_phy *pi, u8 field, u16 value,
+ u8 core_code)
+{
+ u16 mask;
+ u16 val;
+ u8 core;
- write_phy_reg(pi, 0x36, clip1md_gaincode_B);
- write_phy_reg(pi, 0x2ac, clip1md_gaincode_B);
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+ if (core_code == RADIO_MIMO_CORESEL_CORE1
+ && core == PHY_CORE_1)
+ continue;
+ else if (core_code == RADIO_MIMO_CORESEL_CORE2
+ && core == PHY_CORE_0)
+ continue;
- write_phy_reg(pi, 0x37, clip1lo_gaincode);
- write_phy_reg(pi, 0x2ad, clip1lo_gaincode);
- write_phy_reg(pi, 0x38, clip1lo_gaincode_B);
- write_phy_reg(pi, 0x2ae, clip1lo_gaincode_B);
+ if (NREV_LT(pi->pubpi.phy_rev, 7)) {
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8,
- tia_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8,
- tia_gain_db);
+ mask = (0x1 << 10);
+ val = 1 << 10;
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 :
+ 0x92, mask, val);
+ }
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8,
- tia_gainbits);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8,
- tia_gainbits);
+ if (field == NPHY_RfctrlIntc_override_OFF) {
- mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0));
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 :
+ 0x92, 0);
- if (chg_nbclip_th == 1) {
- write_phy_reg(pi, 0x2b, nbclip_th);
- write_phy_reg(pi, 0x41, nbclip_th);
- }
+ wlc_phy_force_rfseq_nphy(pi,
+ NPHY_RFSEQ_RESET2RX);
+ } else if (field == NPHY_RfctrlIntc_override_TRSW) {
- mod_phy_reg(pi, 0x300, (0x3f << 0), (w1clip_th << 0));
- mod_phy_reg(pi, 0x301, (0x3f << 0), (w1clip_th << 0));
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- mod_phy_reg(pi, 0x2e4,
- (0x3f << 0), (nvar_baseline_offset0 << 0));
+ mask = (0x1 << 6) | (0x1 << 7);
- mod_phy_reg(pi, 0x2e4,
- (0x3f << 6), (nvar_baseline_offset1 << 6));
+ val = value << 6;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
- if (CHSPEC_IS20(pi->radio_chanspec)) {
+ or_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ (0x1 << 10));
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8,
- lna1_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8,
- lna1_gain_db_2);
+ and_phy_reg(pi, 0x2ff, (u16)
+ ~(0x3 << 14));
+ or_phy_reg(pi, 0x2ff, (0x1 << 13));
+ or_phy_reg(pi, 0x2ff, (0x1 << 0));
+ } else {
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10,
- 8, lna2_gain_db);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10,
- 8, lna2_gain_db);
+ mask = (0x1 << 6) |
+ (0x1 << 7) |
+ (0x1 << 8) | (0x1 << 9);
+ val = value << 6;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
- write_phy_reg(pi, 0x24, clip1md_gaincode);
- write_phy_reg(pi, 0x2ab, clip1md_gaincode);
- } else {
- mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0));
- }
+ mask = (0x1 << 0);
+ val = 1 << 0;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xe7 : 0xec,
+ mask, val);
- }
+ mask = (core == PHY_CORE_0) ?
+ (0x1 << 0) : (0x1 << 1);
+ val = 1 << ((core == PHY_CORE_0) ?
+ 0 : 1);
+ mod_phy_reg(pi, 0x78, mask, val);
+
+ SPINWAIT(((read_phy_reg(pi, 0x78) & val)
+ != 0), 10000);
+ if (WARN(read_phy_reg(pi, 0x78) & val,
+ "HW error: override failed"))
+ return;
+
+ mask = (0x1 << 0);
+ val = 0 << 0;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0xe7 : 0xec,
+ mask, val);
+ }
+ } else if (field == NPHY_RfctrlIntc_override_PA) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ mask = (0x1 << 4) | (0x1 << 5);
+
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ val = value << 5;
+ else
+ val = value << 4;
+
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ or_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ (0x1 << 12));
+ } else {
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mask = (0x1 << 5);
+ val = value << 5;
+ } else {
+ mask = (0x1 << 4);
+ val = value << 4;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ }
+ } else if (field ==
+ NPHY_RfctrlIntc_override_EXT_LNA_PU) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+
+ mask = (0x1 << 0);
+ val = value << 0;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 2);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ } else {
+
+ mask = (0x1 << 2);
+ val = value << 2;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 0);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ }
+
+ mask = (0x1 << 11);
+ val = 1 << 11;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ } else {
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mask = (0x1 << 0);
+ val = value << 0;
+ } else {
+ mask = (0x1 << 2);
+ val = value << 2;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ }
+ } else if (field ==
+ NPHY_RfctrlIntc_override_EXT_LNA_GAIN) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+
+ mask = (0x1 << 1);
+ val = value << 1;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 3);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ } else {
+
+ mask = (0x1 << 3);
+ val = value << 3;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, val);
+
+ mask = (0x1 << 1);
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91
+ : 0x92, mask, 0);
+ }
+
+ mask = (0x1 << 11);
+ val = 1 << 11;
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ } else {
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ mask = (0x1 << 1);
+ val = value << 1;
+ } else {
+ mask = (0x1 << 3);
+ val = value << 3;
+ }
+ mod_phy_reg(pi,
+ (core ==
+ PHY_CORE_0) ? 0x91 : 0x92,
+ mask, val);
+ }
+ }
+ }
+ }
}
-static void wlc_phy_adjust_lnagaintbl_nphy(struct brcms_phy *pi)
+void
+wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, s32 dBm_targetpower,
+ bool debug)
{
+ int gainctrl_loopidx;
uint core;
- int ctr;
- s16 gain_delta[2];
- u8 curr_channel;
- u16 minmax_gain[2];
- u16 regval[4];
+ u16 m0m1, curr_m0m1;
+ s32 delta_power;
+ s32 txpwrindex;
+ s32 qdBm_power[2];
+ u16 orig_BBConfig;
+ u16 phy_saveregs[4];
+ u32 freq_test;
+ u16 ampl_test = 250;
+ uint stepsize;
+ bool phyhang_avoid_state = false;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ stepsize = 2;
+ else
+ stepsize = 1;
+
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ freq_test = 5000;
+ else
+ freq_test = 2500;
+
+ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true);
+ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true);
if (pi->phyhang_avoid)
wlc_phy_stay_in_carriersearch_nphy(pi, true);
- if (pi->nphy_gain_boost) {
- if ((CHSPEC_IS2G(pi->radio_chanspec))) {
+ phyhang_avoid_state = pi->phyhang_avoid;
+ pi->phyhang_avoid = false;
- gain_delta[0] = 6;
- gain_delta[1] = 6;
- } else {
+ phy_saveregs[0] = read_phy_reg(pi, 0x91);
+ phy_saveregs[1] = read_phy_reg(pi, 0x92);
+ phy_saveregs[2] = read_phy_reg(pi, 0xe7);
+ phy_saveregs[3] = read_phy_reg(pi, 0xec);
+ wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 1,
+ RADIO_MIMO_CORESEL_CORE1 |
+ RADIO_MIMO_CORESEL_CORE2);
- curr_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
- gain_delta[0] =
- (s16)
- PHY_HW_ROUND(((nphy_lnagain_est0[0] *
- curr_channel) +
- nphy_lnagain_est0[1]), 13);
- gain_delta[1] =
- (s16)
- PHY_HW_ROUND(((nphy_lnagain_est1[0] *
- curr_channel) +
- nphy_lnagain_est1[1]), 13);
- }
+ if (!debug) {
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x2, RADIO_MIMO_CORESEL_CORE1);
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x8, RADIO_MIMO_CORESEL_CORE2);
} else {
-
- gain_delta[0] = 0;
- gain_delta[1] = 0;
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x1, RADIO_MIMO_CORESEL_CORE1);
+ wlc_phy_rfctrlintc_override_nphy(pi,
+ NPHY_RfctrlIntc_override_TRSW,
+ 0x7, RADIO_MIMO_CORESEL_CORE2);
}
+ orig_BBConfig = read_phy_reg(pi, 0x01);
+ mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1);
+
for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- if (pi->nphy_elna_gain_config) {
+ txpwrindex = (s32) pi->nphy_cal_orig_pwr_idx[core];
- regval[0] = nphy_def_lnagains[2] + gain_delta[core];
- regval[1] = nphy_def_lnagains[3] + gain_delta[core];
- regval[2] = nphy_def_lnagains[3] + gain_delta[core];
- regval[3] = nphy_def_lnagains[3] + gain_delta[core];
- } else {
- for (ctr = 0; ctr < 4; ctr++) {
- regval[ctr] =
- nphy_def_lnagains[ctr] + gain_delta[core];
+ for (gainctrl_loopidx = 0; gainctrl_loopidx < 2;
+ gainctrl_loopidx++) {
+ wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0,
+ false);
+
+ if (core == PHY_CORE_0)
+ curr_m0m1 = m0m1 & 0xff00;
+ else
+ curr_m0m1 = m0m1 & 0x00ff;
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &curr_m0m1);
+ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &curr_m0m1);
+
+ udelay(50);
+
+ wlc_phy_est_tonepwr_nphy(pi, qdBm_power,
+ NPHY_CAL_TSSISAMPS);
+
+ pi->nphy_bb_mult_save = 0;
+ wlc_phy_stopplayback_nphy(pi);
+
+ delta_power = (dBm_targetpower * 4) - qdBm_power[core];
+
+ txpwrindex -= stepsize * delta_power;
+ if (txpwrindex < 0)
+ txpwrindex = 0;
+ else if (txpwrindex > 127)
+ txpwrindex = 127;
+
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(pi->pubpi.phy_rev, 4) &&
+ (pi->srom_fem5g.extpagain == 3)) {
+ if (txpwrindex < 30)
+ txpwrindex = 30;
+ }
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 5) &&
+ (pi->srom_fem2g.extpagain == 3)) {
+ if (txpwrindex < 50)
+ txpwrindex = 50;
+ }
}
+
+ wlc_phy_txpwr_index_nphy(pi, (1 << core),
+ (u8) txpwrindex, true);
}
- wlc_phy_table_write_nphy(pi, core, 4, 8, 16, regval);
- minmax_gain[core] =
- (u16) (nphy_def_lnagains[2] + gain_delta[core] + 4);
+ pi->nphy_txcal_pwr_idx[core] = (u8) txpwrindex;
+
+ if (debug) {
+ u16 radio_gain;
+ u16 dbg_m0m1;
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &dbg_m0m1);
+
+ wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0,
+ false);
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &dbg_m0m1);
+ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &dbg_m0m1);
+
+ udelay(100);
+
+ wlc_phy_est_tonepwr_nphy(pi, qdBm_power,
+ NPHY_CAL_TSSISAMPS);
+
+ wlc_phy_table_read_nphy(pi, 7, 1, (0x110 + core), 16,
+ &radio_gain);
+
+ mdelay(4000);
+ pi->nphy_bb_mult_save = 0;
+ wlc_phy_stopplayback_nphy(pi);
+ }
}
- mod_phy_reg(pi, 0x1e, (0xff << 0), (minmax_gain[0] << 0));
- mod_phy_reg(pi, 0x34, (0xff << 0), (minmax_gain[1] << 0));
+ wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_txcal_pwr_idx[0], true);
+ wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_txcal_pwr_idx[1], true);
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &pi->nphy_txcal_bbmult);
+
+ write_phy_reg(pi, 0x01, orig_BBConfig);
+
+ write_phy_reg(pi, 0x91, phy_saveregs[0]);
+ write_phy_reg(pi, 0x92, phy_saveregs[1]);
+ write_phy_reg(pi, 0xe7, phy_saveregs[2]);
+ write_phy_reg(pi, 0xec, phy_saveregs[3]);
+
+ pi->phyhang_avoid = phyhang_avoid_state;
if (pi->phyhang_avoid)
wlc_phy_stay_in_carriersearch_nphy(pi, false);
}
-void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on)
+static void wlc_phy_savecal_nphy(struct brcms_phy *pi)
{
- if (on) {
+ void *tbl_ptr;
+ int coreNum;
+ u16 *txcal_radio_regs = NULL;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 0,
+ &pi->calibration_cache.
+ rxcal_coeffs_2G);
+
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (!pi->radio_is_on) {
- wlc_phy_radio_preinit_205x(pi);
- wlc_phy_radio_init_2057(pi);
- wlc_phy_radio_postinit_2057(pi);
- }
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_2G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- wlc_phy_chanspec_set((struct brcms_phy_pub *) pi,
- pi->radio_chanspec);
+ pi->calibration_cache.txcal_radio_regs_2G[0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[1] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[2] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_2G[3] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1);
+
+ pi->calibration_cache.txcal_radio_regs_2G[4] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[5] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_2G[6] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_2G[7] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1);
+ } else {
+ pi->calibration_cache.txcal_radio_regs_2G[0] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_2G[1] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_2G[2] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM);
+ pi->calibration_cache.txcal_radio_regs_2G[3] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM);
+ }
+
+ pi->nphy_iqcal_chanspec_2G = pi->radio_chanspec;
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_2G;
+ } else {
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 0,
+ &pi->calibration_cache.
+ rxcal_coeffs_5G);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_5G;
} else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- wlc_phy_radio_preinit_205x(pi);
- wlc_phy_radio_init_2056(pi);
- wlc_phy_radio_postinit_2056(pi);
- wlc_phy_chanspec_set((struct brcms_phy_pub *) pi,
- pi->radio_chanspec);
+ pi->calibration_cache.txcal_radio_regs_5G[0] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[1] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[2] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_5G[3] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1);
+
+ pi->calibration_cache.txcal_radio_regs_5G[4] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[5] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0);
+ pi->calibration_cache.txcal_radio_regs_5G[6] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1);
+ pi->calibration_cache.txcal_radio_regs_5G[7] =
+ read_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1);
} else {
- wlc_phy_radio_preinit_2055(pi);
- wlc_phy_radio_init_2055(pi);
- wlc_phy_radio_postinit_2055(pi);
+ pi->calibration_cache.txcal_radio_regs_5G[0] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_5G[1] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL);
+ pi->calibration_cache.txcal_radio_regs_5G[2] =
+ read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM);
+ pi->calibration_cache.txcal_radio_regs_5G[3] =
+ read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM);
}
- pi->radio_is_on = true;
+ pi->nphy_iqcal_chanspec_5G = pi->radio_chanspec;
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_5G;
+ }
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+
+ txcal_radio_regs[2 * coreNum] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_I);
+ txcal_radio_regs[2 * coreNum + 1] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_Q);
+
+ txcal_radio_regs[2 * coreNum + 4] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_I);
+ txcal_radio_regs[2 * coreNum + 5] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_Q);
+ }
+ }
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 8, 80, 16, tbl_ptr);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
+static void wlc_phy_tx_iq_war_nphy(struct brcms_phy *pi)
+{
+ struct nphy_iq_comp tx_comp;
+
+ wlc_phy_table_read_nphy(pi, 15, 4, 0x50, 16, &tx_comp);
+
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ, tx_comp.a0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 2, tx_comp.b0);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 4, tx_comp.a1);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 6, tx_comp.b1);
+}
+
+static void wlc_phy_restorecal_nphy(struct brcms_phy *pi)
+{
+ u16 *loft_comp;
+ u16 txcal_coeffs_bphy[4];
+ u16 *tbl_ptr;
+ int coreNum;
+ u16 *txcal_radio_regs = NULL;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->nphy_iqcal_chanspec_2G == 0)
+ return;
+
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_2G;
+ loft_comp = &pi->calibration_cache.txcal_coeffs_2G[5];
} else {
+ if (pi->nphy_iqcal_chanspec_5G == 0)
+ return;
- if (NREV_GE(pi->pubpi.phy_rev, 3)
- && NREV_LT(pi->pubpi.phy_rev, 7)) {
- and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
- mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x0);
+ tbl_ptr = pi->calibration_cache.txcal_coeffs_5G;
+ loft_comp = &pi->calibration_cache.txcal_coeffs_5G[5];
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, 16, tbl_ptr);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ txcal_coeffs_bphy[0] = tbl_ptr[0];
+ txcal_coeffs_bphy[1] = tbl_ptr[1];
+ txcal_coeffs_bphy[2] = tbl_ptr[2];
+ txcal_coeffs_bphy[3] = tbl_ptr[3];
+ } else {
+ txcal_coeffs_bphy[0] = 0;
+ txcal_coeffs_bphy[1] = 0;
+ txcal_coeffs_bphy[2] = 0;
+ txcal_coeffs_bphy[3] = 0;
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, 16,
+ txcal_coeffs_bphy);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, 16, loft_comp);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, 16, loft_comp);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
+ wlc_phy_tx_iq_war_nphy(pi);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_2G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
write_radio_reg(pi,
- RADIO_2056_TX_PADA_BOOST_TUNE |
- RADIO_2056_TX0, 0);
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[0]);
write_radio_reg(pi,
- RADIO_2056_TX_PADG_BOOST_TUNE |
- RADIO_2056_TX0, 0);
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[1]);
write_radio_reg(pi,
- RADIO_2056_TX_PGAA_BOOST_TUNE |
- RADIO_2056_TX0, 0);
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[2]);
write_radio_reg(pi,
- RADIO_2056_TX_PGAG_BOOST_TUNE |
- RADIO_2056_TX0, 0);
- mod_radio_reg(pi,
- RADIO_2056_TX_MIXA_BOOST_TUNE |
- RADIO_2056_TX0, 0xf0, 0);
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[3]);
+
write_radio_reg(pi,
- RADIO_2056_TX_MIXG_BOOST_TUNE |
- RADIO_2056_TX0, 0);
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[4]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[5]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[6]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[7]);
+ } else {
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[0]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[1]);
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[2]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_2G[3]);
+ }
+
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1,
+ &pi->calibration_cache.
+ rxcal_coeffs_2G);
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ txcal_radio_regs =
+ pi->calibration_cache.txcal_radio_regs_5G;
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
write_radio_reg(pi,
- RADIO_2056_TX_PADA_BOOST_TUNE |
- RADIO_2056_TX1, 0);
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[0]);
write_radio_reg(pi,
- RADIO_2056_TX_PADG_BOOST_TUNE |
- RADIO_2056_TX1, 0);
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[1]);
write_radio_reg(pi,
- RADIO_2056_TX_PGAA_BOOST_TUNE |
- RADIO_2056_TX1, 0);
+ RADIO_2056_TX_LOFT_FINE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[2]);
write_radio_reg(pi,
- RADIO_2056_TX_PGAG_BOOST_TUNE |
- RADIO_2056_TX1, 0);
- mod_radio_reg(pi,
- RADIO_2056_TX_MIXA_BOOST_TUNE |
- RADIO_2056_TX1, 0xf0, 0);
+ RADIO_2056_TX_LOFT_FINE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[3]);
+
write_radio_reg(pi,
- RADIO_2056_TX_MIXG_BOOST_TUNE |
- RADIO_2056_TX1, 0);
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[4]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX0,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[5]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_I |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[6]);
+ write_radio_reg(pi,
+ RADIO_2056_TX_LOFT_COARSE_Q |
+ RADIO_2056_TX1,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[7]);
+ } else {
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[0]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[1]);
+ write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[2]);
+ write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM,
+ pi->calibration_cache.
+ txcal_radio_regs_5G[3]);
+ }
- pi->radio_is_on = false;
+ wlc_phy_rx_iq_coeffs_nphy(pi, 1,
+ &pi->calibration_cache.
+ rxcal_coeffs_5G);
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ for (coreNum = 0; coreNum <= 1; coreNum++) {
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_I,
+ txcal_radio_regs[2 * coreNum]);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_FINE_Q,
+ txcal_radio_regs[2 * coreNum + 1]);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_I,
+ txcal_radio_regs[2 * coreNum + 4]);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
+ LOFT_COARSE_Q,
+ txcal_radio_regs[2 * coreNum + 5]);
}
+ }
+}
- if (NREV_GE(pi->pubpi.phy_rev, 8)) {
- and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
- pi->radio_is_on = false;
+static void wlc_phy_txpwrctrl_coeff_setup_nphy(struct brcms_phy *pi)
+{
+ u32 idx;
+ u16 iqloCalbuf[7];
+ u32 iqcomp, locomp, curr_locomp;
+ s8 locomp_i, locomp_q;
+ s8 curr_locomp_i, curr_locomp_q;
+ u32 tbl_id, tbl_len, tbl_offset;
+ u32 regval[128];
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ wlc_phy_table_read_nphy(pi, 15, 7, 80, 16, iqloCalbuf);
+
+ tbl_len = 128;
+ tbl_offset = 320;
+ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
+ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
+ iqcomp =
+ (tbl_id ==
+ 26) ? (((u32) (iqloCalbuf[0] & 0x3ff)) << 10) |
+ (iqloCalbuf[1] & 0x3ff)
+ : (((u32) (iqloCalbuf[2] & 0x3ff)) << 10) |
+ (iqloCalbuf[3] & 0x3ff);
+
+ for (idx = 0; idx < tbl_len; idx++)
+ regval[idx] = iqcomp;
+ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
+ regval);
+ }
+
+ tbl_offset = 448;
+ for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
+ tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
+
+ locomp =
+ (u32) ((tbl_id == 26) ? iqloCalbuf[5] : iqloCalbuf[6]);
+ locomp_i = (s8) ((locomp >> 8) & 0xff);
+ locomp_q = (s8) ((locomp) & 0xff);
+ for (idx = 0; idx < tbl_len; idx++) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ curr_locomp_i = locomp_i;
+ curr_locomp_q = locomp_q;
+ } else {
+ curr_locomp_i = (s8) ((locomp_i *
+ nphy_tpc_loscale[idx] +
+ 128) >> 8);
+ curr_locomp_q =
+ (s8) ((locomp_q *
+ nphy_tpc_loscale[idx] +
+ 128) >> 8);
+ }
+ curr_locomp = (u32) ((curr_locomp_i & 0xff) << 8);
+ curr_locomp |= (u32) (curr_locomp_q & 0xff);
+ regval[idx] = curr_locomp;
}
+ wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
+ regval);
+ }
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX1, 0xFFFF);
+ wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX2, 0xFFFF);
}
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
}
-static void wlc_phy_radio_preinit_2055(struct brcms_phy *pi)
+static void wlc_phy_txlpfbw_nphy(struct brcms_phy *pi)
{
+ u8 tx_lpf_bw = 0;
- and_phy_reg(pi, 0x78, ~RFCC_POR_FORCE);
- or_phy_reg(pi, 0x78, RFCC_CHIP0_PU | RFCC_OE_POR_FORCE);
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ tx_lpf_bw = 3;
+ else
+ tx_lpf_bw = 1;
- or_phy_reg(pi, 0x78, RFCC_POR_FORCE);
+ if (PHY_IPA(pi)) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ tx_lpf_bw = 5;
+ else
+ tx_lpf_bw = 4;
+ }
+
+ write_phy_reg(pi, 0xe8,
+ (tx_lpf_bw << 0) |
+ (tx_lpf_bw << 3) |
+ (tx_lpf_bw << 6) | (tx_lpf_bw << 9));
+
+ if (PHY_IPA(pi)) {
+
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ tx_lpf_bw = 4;
+ else
+ tx_lpf_bw = 1;
+
+ write_phy_reg(pi, 0xe9,
+ (tx_lpf_bw << 0) |
+ (tx_lpf_bw << 3) |
+ (tx_lpf_bw << 6) | (tx_lpf_bw << 9));
+ }
+ }
}
-static void wlc_phy_radio_init_2055(struct brcms_phy *pi)
+static void
+wlc_phy_adjust_rx_analpfbw_nphy(struct brcms_phy *pi, u16 reduction_factr)
{
- wlc_phy_init_radio_regs(pi, regs_2055, RADIO_DEFAULT_CORE);
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) &&
+ CHSPEC_IS40(pi->radio_chanspec)) {
+ if (!pi->nphy_anarxlpf_adjusted) {
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ RADIO_2056_RX0),
+ ((pi->nphy_rccal_value +
+ reduction_factr) | 0x80));
+
+ pi->nphy_anarxlpf_adjusted = true;
+ }
+ } else {
+ if (pi->nphy_anarxlpf_adjusted) {
+ write_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_LPC |
+ RADIO_2056_RX0),
+ (pi->nphy_rccal_value | 0x80));
+
+ pi->nphy_anarxlpf_adjusted = false;
+ }
+ }
+ }
}
-static void wlc_phy_radio_postinit_2055(struct brcms_phy *pi)
+static void
+wlc_phy_adjust_min_noisevar_nphy(struct brcms_phy *pi, int ntones,
+ int *tone_id_buf, u32 *noise_var_buf)
{
+ int i;
+ u32 offset;
+ int tone_id;
+ int tbllen =
+ CHSPEC_IS40(pi->radio_chanspec) ?
+ NPHY_NOISEVAR_TBLLEN40 : NPHY_NOISEVAR_TBLLEN20;
- and_radio_reg(pi, RADIO_2055_MASTER_CNTRL1,
- ~(RADIO_2055_JTAGCTRL_MASK | RADIO_2055_JTAGSYNC_MASK));
+ if (pi->nphy_noisevars_adjusted) {
+ for (i = 0; i < pi->nphy_saved_noisevars.bufcount; i++) {
+ tone_id = pi->nphy_saved_noisevars.tone_id[i];
+ offset = (tone_id >= 0) ?
+ ((tone_id *
+ 2) + 1) : (tbllen + (tone_id * 2) + 1);
+ wlc_phy_table_write_nphy(
+ pi, NPHY_TBL_ID_NOISEVAR, 1,
+ offset, 32,
+ &pi->nphy_saved_noisevars.min_noise_vars[i]);
+ }
- if (((pi->sh->sromrev >= 4)
- && !(pi->sh->boardflags2 & BFL2_RXBB_INT_REG_DIS))
- || ((pi->sh->sromrev < 4))) {
- and_radio_reg(pi, RADIO_2055_CORE1_RXBB_REGULATOR, 0x7F);
- and_radio_reg(pi, RADIO_2055_CORE2_RXBB_REGULATOR, 0x7F);
+ pi->nphy_saved_noisevars.bufcount = 0;
+ pi->nphy_noisevars_adjusted = false;
}
- mod_radio_reg(pi, RADIO_2055_RRCCAL_N_OPT_SEL, 0x3F, 0x2C);
- write_radio_reg(pi, RADIO_2055_CAL_MISC, 0x3C);
+ if ((noise_var_buf != NULL) && (tone_id_buf != NULL)) {
+ pi->nphy_saved_noisevars.bufcount = 0;
- and_radio_reg(pi, RADIO_2055_CAL_MISC,
- ~(RADIO_2055_RRCAL_START | RADIO_2055_RRCAL_RST_N));
+ for (i = 0; i < ntones; i++) {
+ tone_id = tone_id_buf[i];
+ offset = (tone_id >= 0) ?
+ ((tone_id * 2) + 1) :
+ (tbllen + (tone_id * 2) + 1);
+ pi->nphy_saved_noisevars.tone_id[i] = tone_id;
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ offset, 32,
+ &pi->nphy_saved_noisevars.
+ min_noise_vars[i]);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
+ offset, 32, &noise_var_buf[i]);
+ pi->nphy_saved_noisevars.bufcount++;
+ }
- or_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, RADIO_2055_CAL_LPO_ENABLE);
+ pi->nphy_noisevars_adjusted = true;
+ }
+}
- or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_RST_N);
+static void wlc_phy_adjust_crsminpwr_nphy(struct brcms_phy *pi, u8 minpwr)
+{
+ u16 regval;
- udelay(1000);
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) &&
+ CHSPEC_IS40(pi->radio_chanspec)) {
+ if (!pi->nphy_crsminpwr_adjusted) {
+ regval = read_phy_reg(pi, 0x27d);
+ pi->nphy_crsminpwr[0] = regval & 0xff;
+ regval &= 0xff00;
+ regval |= (u16) minpwr;
+ write_phy_reg(pi, 0x27d, regval);
- or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_START);
+ regval = read_phy_reg(pi, 0x280);
+ pi->nphy_crsminpwr[1] = regval & 0xff;
+ regval &= 0xff00;
+ regval |= (u16) minpwr;
+ write_phy_reg(pi, 0x280, regval);
- SPINWAIT(((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) &
- RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE), 2000);
+ regval = read_phy_reg(pi, 0x283);
+ pi->nphy_crsminpwr[2] = regval & 0xff;
+ regval &= 0xff00;
+ regval |= (u16) minpwr;
+ write_phy_reg(pi, 0x283, regval);
- if (WARN((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) &
- RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE,
- "HW error: radio calibration1\n"))
+ pi->nphy_crsminpwr_adjusted = true;
+ }
+ } else {
+ if (pi->nphy_crsminpwr_adjusted) {
+ regval = read_phy_reg(pi, 0x27d);
+ regval &= 0xff00;
+ regval |= pi->nphy_crsminpwr[0];
+ write_phy_reg(pi, 0x27d, regval);
+
+ regval = read_phy_reg(pi, 0x280);
+ regval &= 0xff00;
+ regval |= pi->nphy_crsminpwr[1];
+ write_phy_reg(pi, 0x280, regval);
+
+ regval = read_phy_reg(pi, 0x283);
+ regval &= 0xff00;
+ regval |= pi->nphy_crsminpwr[2];
+ write_phy_reg(pi, 0x283, regval);
+
+ pi->nphy_crsminpwr_adjusted = false;
+ }
+ }
+ }
+}
+
+static void wlc_phy_spurwar_nphy(struct brcms_phy *pi)
+{
+ u16 cur_channel = 0;
+ int nphy_adj_tone_id_buf[] = { 57, 58 };
+ u32 nphy_adj_noise_var_buf[] = { 0x3ff, 0x3ff };
+ bool isAdjustNoiseVar = false;
+ uint numTonesAdjust = 0;
+ u32 tempval = 0;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ cur_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
+
+ if (pi->nphy_gband_spurwar_en) {
+
+ wlc_phy_adjust_rx_analpfbw_nphy(
+ pi,
+ NPHY_ANARXLPFBW_REDUCTIONFACT);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((cur_channel == 11)
+ && CHSPEC_IS40(pi->radio_chanspec))
+ wlc_phy_adjust_min_noisevar_nphy(
+ pi, 2,
+ nphy_adj_tone_id_buf,
+ nphy_adj_noise_var_buf);
+ else
+ wlc_phy_adjust_min_noisevar_nphy(pi, 0,
+ NULL,
+ NULL);
+ }
+
+ wlc_phy_adjust_crsminpwr_nphy(pi,
+ NPHY_ADJUSTED_MINCRSPOWER);
+ }
+
+ if ((pi->nphy_gband_spurwar2_en)
+ && CHSPEC_IS2G(pi->radio_chanspec)) {
+
+ if (CHSPEC_IS40(pi->radio_chanspec)) {
+ switch (cur_channel) {
+ case 3:
+ nphy_adj_tone_id_buf[0] = 57;
+ nphy_adj_tone_id_buf[1] = 58;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 4:
+ nphy_adj_tone_id_buf[0] = 41;
+ nphy_adj_tone_id_buf[1] = 42;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 5:
+ nphy_adj_tone_id_buf[0] = 25;
+ nphy_adj_tone_id_buf[1] = 26;
+ nphy_adj_noise_var_buf[0] = 0x24f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 6:
+ nphy_adj_tone_id_buf[0] = 9;
+ nphy_adj_tone_id_buf[1] = 10;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ case 7:
+ nphy_adj_tone_id_buf[0] = 121;
+ nphy_adj_tone_id_buf[1] = 122;
+ nphy_adj_noise_var_buf[0] = 0x18f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ case 8:
+ nphy_adj_tone_id_buf[0] = 105;
+ nphy_adj_tone_id_buf[1] = 106;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x25f;
+ isAdjustNoiseVar = true;
+ break;
+ case 9:
+ nphy_adj_tone_id_buf[0] = 89;
+ nphy_adj_tone_id_buf[1] = 90;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ case 10:
+ nphy_adj_tone_id_buf[0] = 73;
+ nphy_adj_tone_id_buf[1] = 74;
+ nphy_adj_noise_var_buf[0] = 0x22f;
+ nphy_adj_noise_var_buf[1] = 0x24f;
+ isAdjustNoiseVar = true;
+ break;
+ default:
+ isAdjustNoiseVar = false;
+ break;
+ }
+ }
+
+ if (isAdjustNoiseVar) {
+ numTonesAdjust = sizeof(nphy_adj_tone_id_buf) /
+ sizeof(nphy_adj_tone_id_buf[0]);
+
+ wlc_phy_adjust_min_noisevar_nphy(
+ pi,
+ numTonesAdjust,
+ nphy_adj_tone_id_buf,
+ nphy_adj_noise_var_buf);
+
+ tempval = 0;
+
+ } else {
+ wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL,
+ NULL);
+ }
+ }
+
+ if ((pi->nphy_aband_spurwar_en) &&
+ (CHSPEC_IS5G(pi->radio_chanspec))) {
+ switch (cur_channel) {
+ case 54:
+ nphy_adj_tone_id_buf[0] = 32;
+ nphy_adj_noise_var_buf[0] = 0x25f;
+ break;
+ case 38:
+ case 102:
+ case 118:
+ nphy_adj_tone_id_buf[0] = 0;
+ nphy_adj_noise_var_buf[0] = 0x0;
+ break;
+ case 134:
+ nphy_adj_tone_id_buf[0] = 32;
+ nphy_adj_noise_var_buf[0] = 0x21f;
+ break;
+ case 151:
+ nphy_adj_tone_id_buf[0] = 16;
+ nphy_adj_noise_var_buf[0] = 0x23f;
+ break;
+ case 153:
+ case 161:
+ nphy_adj_tone_id_buf[0] = 48;
+ nphy_adj_noise_var_buf[0] = 0x23f;
+ break;
+ default:
+ nphy_adj_tone_id_buf[0] = 0;
+ nphy_adj_noise_var_buf[0] = 0x0;
+ break;
+ }
+
+ if (nphy_adj_tone_id_buf[0]
+ && nphy_adj_noise_var_buf[0])
+ wlc_phy_adjust_min_noisevar_nphy(
+ pi, 1,
+ nphy_adj_tone_id_buf,
+ nphy_adj_noise_var_buf);
+ else
+ wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL,
+ NULL);
+ }
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+ }
+}
+
+void wlc_phy_init_nphy(struct brcms_phy *pi)
+{
+ u16 val;
+ u16 clip1_ths[2];
+ struct nphy_txgains target_gain;
+ u8 tx_pwr_ctrl_state;
+ bool do_nphy_cal = false;
+ uint core;
+ uint origidx, intr_val;
+ struct d11regs __iomem *regs;
+ u32 d11_clk_ctl_st;
+ bool do_rssi_cal = false;
+
+ core = 0;
+
+ if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN))
+ pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC;
+
+ if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) &&
+ ((pi->sh->chippkg == BCM4717_PKG_ID) ||
+ (pi->sh->chippkg == BCM4718_PKG_ID))) {
+ if ((pi->sh->boardflags & BFL_EXTLNA) &&
+ (CHSPEC_IS2G(pi->radio_chanspec)))
+ ai_corereg(pi->sh->sih, SI_CC_IDX,
+ offsetof(struct chipcregs, chipcontrol),
+ 0x40, 0x40);
+ }
+
+ if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) &&
+ CHSPEC_IS40(pi->radio_chanspec)) {
+
+ regs = (struct d11regs __iomem *)
+ ai_switch_core(pi->sh->sih,
+ D11_CORE_ID, &origidx,
+ &intr_val);
+ d11_clk_ctl_st = R_REG(&regs->clk_ctl_st);
+ AND_REG(&regs->clk_ctl_st,
+ ~(CCS_FORCEHT | CCS_HTAREQ));
+
+ W_REG(&regs->clk_ctl_st, d11_clk_ctl_st);
+
+ ai_restore_core(pi->sh->sih, origidx, intr_val);
+ }
+
+ pi->use_int_tx_iqlo_cal_nphy =
+ (PHY_IPA(pi) ||
+ (NREV_GE(pi->pubpi.phy_rev, 7) ||
+ (NREV_GE(pi->pubpi.phy_rev, 5)
+ && pi->sh->boardflags2 & BFL2_INTERNDET_TXIQCAL)));
+
+ pi->internal_tx_iqlo_cal_tapoff_intpa_nphy = false;
+
+ pi->nphy_deaf_count = 0;
+
+ wlc_phy_tbl_init_nphy(pi);
+
+ pi->nphy_crsminpwr_adjusted = false;
+ pi->nphy_noisevars_adjusted = false;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0xe7, 0);
+ write_phy_reg(pi, 0xec, 0);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_phy_reg(pi, 0x342, 0);
+ write_phy_reg(pi, 0x343, 0);
+ write_phy_reg(pi, 0x346, 0);
+ write_phy_reg(pi, 0x347, 0);
+ }
+ write_phy_reg(pi, 0xe5, 0);
+ write_phy_reg(pi, 0xe6, 0);
+ } else {
+ write_phy_reg(pi, 0xec, 0);
+ }
+
+ write_phy_reg(pi, 0x91, 0);
+ write_phy_reg(pi, 0x92, 0);
+ if (NREV_LT(pi->pubpi.phy_rev, 6)) {
+ write_phy_reg(pi, 0x93, 0);
+ write_phy_reg(pi, 0x94, 0);
+ }
+
+ and_phy_reg(pi, 0xa1, ~3);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ write_phy_reg(pi, 0x8f, 0);
+ write_phy_reg(pi, 0xa5, 0);
+ } else {
+ write_phy_reg(pi, 0xa5, 0);
+ }
+
+ if (NREV_IS(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b);
+ else if (NREV_LT(pi->pubpi.phy_rev, 2))
+ mod_phy_reg(pi, 0xdc, 0x00ff, 0x40);
+
+ write_phy_reg(pi, 0x203, 32);
+ write_phy_reg(pi, 0x201, 32);
+
+ if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD)
+ write_phy_reg(pi, 0x20d, 160);
+ else
+ write_phy_reg(pi, 0x20d, 184);
+
+ write_phy_reg(pi, 0x13a, 200);
+
+ write_phy_reg(pi, 0x70, 80);
+
+ write_phy_reg(pi, 0x1ff, 48);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 8))
+ wlc_phy_update_mimoconfig_nphy(pi, pi->n_preamble_override);
+
+ wlc_phy_stf_chain_upd_nphy(pi);
+
+ if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ write_phy_reg(pi, 0x180, 0xaa8);
+ write_phy_reg(pi, 0x181, 0x9a4);
+ }
+
+ if (PHY_IPA(pi)) {
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x298 :
+ 0x29c, (0x1ff << 7),
+ (pi->nphy_papd_epsilon_offset[core]) << 7);
+
+ }
+
+ wlc_phy_ipa_set_tx_digi_filts_nphy(pi);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 5)) {
+ wlc_phy_extpa_set_tx_digi_filts_nphy(pi);
+ }
+
+ wlc_phy_workarounds_nphy(pi);
+
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
+
+ val = read_phy_reg(pi, 0x01);
+ write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA);
+ write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA));
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
+
+ wlapi_bmac_macphyclk_set(pi->sh->physhim, ON);
+
+ wlc_phy_pa_override_nphy(pi, OFF);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+ wlc_phy_pa_override_nphy(pi, ON);
+
+ wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_clip_det_nphy(pi, 0, clip1_ths);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ wlc_phy_bphy_init_nphy(pi);
+
+ tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
+ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+
+ wlc_phy_txpwr_fixpower_nphy(pi);
+
+ wlc_phy_txpwrctrl_idle_tssi_nphy(pi);
+
+ wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ u32 *tx_pwrctrl_tbl = NULL;
+ u16 idx;
+ s16 pga_gn = 0;
+ s16 pad_gn = 0;
+ s32 rfpwr_offset;
+
+ if (PHY_IPA(pi)) {
+ tx_pwrctrl_tbl = wlc_phy_get_ipa_gaintbl_nphy(pi);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(pi->pubpi.phy_rev, 3))
+ tx_pwrctrl_tbl =
+ nphy_tpc_5GHz_txgain_rev3;
+ else if (NREV_IS(pi->pubpi.phy_rev, 4))
+ tx_pwrctrl_tbl =
+ (pi->srom_fem5g.extpagain ==
+ 3) ?
+ nphy_tpc_5GHz_txgain_HiPwrEPA :
+ nphy_tpc_5GHz_txgain_rev4;
+ else
+ tx_pwrctrl_tbl =
+ nphy_tpc_5GHz_txgain_rev5;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (pi->pubpi.radiorev == 5)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev5;
+ else if (pi->pubpi.radiorev == 3)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev3;
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 5) &&
+ (pi->srom_fem2g.extpagain == 3))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_HiPwrEPA;
+ else
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_rev3;
+ }
+ }
+ }
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128,
+ 192, 32, tx_pwrctrl_tbl);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128,
+ 192, 32, tx_pwrctrl_tbl);
+
+ pi->nphy_gmval = (u16) ((*tx_pwrctrl_tbl >> 16) & 0x7000);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ for (idx = 0; idx < 128; idx++) {
+ pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf;
+ pad_gn = (tx_pwrctrl_tbl[idx] >> 19) & 0x1f;
+ rfpwr_offset = get_rf_pwr_offset(pi, pga_gn,
+ pad_gn);
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE1TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE2TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ }
+ } else {
+
+ for (idx = 0; idx < 128; idx++) {
+ pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf;
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ rfpwr_offset = (s16)
+ nphy_papd_pga_gain_delta_ipa_2g
+ [pga_gn];
+ else
+ rfpwr_offset = (s16)
+ nphy_papd_pga_gain_delta_ipa_5g
+ [pga_gn];
+
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE1TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_CORE2TXPWRCTL,
+ 1, 576 + idx, 32,
+ &rfpwr_offset);
+ }
+
+ }
+ } else {
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128,
+ 192, 32, nphy_tpc_txgain);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128,
+ 192, 32, nphy_tpc_txgain);
+ }
+
+ if (pi->sh->phyrxchain != 0x3)
+ wlc_phy_rxcore_setstate_nphy((struct brcms_phy_pub *) pi,
+ pi->sh->phyrxchain);
+
+ if (PHY_PERICAL_MPHASE_PENDING(pi))
+ wlc_phy_cal_perical_mphase_restart(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ do_rssi_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ?
+ (pi->nphy_rssical_chanspec_2G == 0) :
+ (pi->nphy_rssical_chanspec_5G == 0);
+
+ if (do_rssi_cal)
+ wlc_phy_rssi_cal_nphy(pi);
+ else
+ wlc_phy_restore_rssical_nphy(pi);
+ } else {
+ wlc_phy_rssi_cal_nphy(pi);
+ }
+
+ if (!SCAN_RM_IN_PROGRESS(pi))
+ do_nphy_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ?
+ (pi->nphy_iqcal_chanspec_2G == 0) :
+ (pi->nphy_iqcal_chanspec_5G == 0);
+
+ if (!pi->do_initcal)
+ do_nphy_cal = false;
+
+ if (do_nphy_cal) {
+
+ target_gain = wlc_phy_get_tx_gain_nphy(pi);
+
+ if (pi->antsel_type == ANTSEL_2x3)
+ wlc_phy_antsel_init((struct brcms_phy_pub *) pi,
+ true);
+
+ if (pi->nphy_perical != PHY_PERICAL_MPHASE) {
+ wlc_phy_rssi_cal_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ pi->nphy_cal_orig_pwr_idx[0] =
+ pi->nphy_txpwrindex[PHY_CORE_0]
+ .
+ index_internal;
+ pi->nphy_cal_orig_pwr_idx[1] =
+ pi->nphy_txpwrindex[PHY_CORE_1]
+ .
+ index_internal;
+
+ wlc_phy_precal_txgain_nphy(pi);
+ target_gain =
+ wlc_phy_get_tx_gain_nphy(pi);
+ }
+
+ if (wlc_phy_cal_txiqlo_nphy
+ (pi, target_gain, true,
+ false) == 0) {
+ if (wlc_phy_cal_rxiq_nphy
+ (pi, target_gain, 2,
+ false) == 0)
+ wlc_phy_savecal_nphy(pi);
+
+ }
+ } else if (pi->mphase_cal_phase_id ==
+ MPHASE_CAL_STATE_IDLE) {
+ wlc_phy_cal_perical((struct brcms_phy_pub *) pi,
+ PHY_PERICAL_PHYINIT);
+ }
+ } else {
+ wlc_phy_restorecal_nphy(pi);
+ }
+
+ wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state);
+
+ wlc_phy_nphy_tkip_rifs_war(pi, pi->sh->_rifs_phy);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LE(pi->pubpi.phy_rev, 6))
+
+ write_phy_reg(pi, 0x70, 50);
+
+ wlc_phy_txlpfbw_nphy(pi);
+
+ wlc_phy_spurwar_nphy(pi);
+
+}
+
+static void wlc_phy_resetcca_nphy(struct brcms_phy *pi)
+{
+ u16 val;
+
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON);
+
+ val = read_phy_reg(pi, 0x01);
+ write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA);
+ udelay(1);
+ write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA));
+
+ wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
+
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+}
+
+void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en)
+{
+ u16 rfctrlintc_override_val;
+
+ if (!en) {
+
+ pi->rfctrlIntc1_save = read_phy_reg(pi, 0x91);
+ pi->rfctrlIntc2_save = read_phy_reg(pi, 0x92);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ rfctrlintc_override_val = 0x1480;
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
+ rfctrlintc_override_val =
+ CHSPEC_IS5G(pi->radio_chanspec) ? 0x600 : 0x480;
+ else
+ rfctrlintc_override_val =
+ CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120;
+
+ write_phy_reg(pi, 0x91, rfctrlintc_override_val);
+ write_phy_reg(pi, 0x92, rfctrlintc_override_val);
+ } else {
+ write_phy_reg(pi, 0x91, pi->rfctrlIntc1_save);
+ write_phy_reg(pi, 0x92, pi->rfctrlIntc2_save);
+ }
+
+}
+
+void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi)
+{
+
+ u16 txrx_chain =
+ (NPHY_RfseqCoreActv_TxRxChain0 | NPHY_RfseqCoreActv_TxRxChain1);
+ bool CoreActv_override = false;
+
+ if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN0) {
+ txrx_chain = NPHY_RfseqCoreActv_TxRxChain0;
+ CoreActv_override = true;
+
+ if (NREV_LE(pi->pubpi.phy_rev, 2))
+ and_phy_reg(pi, 0xa0, ~0x20);
+ } else if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN1) {
+ txrx_chain = NPHY_RfseqCoreActv_TxRxChain1;
+ CoreActv_override = true;
+
+ if (NREV_LE(pi->pubpi.phy_rev, 2))
+ or_phy_reg(pi, 0xa0, 0x20);
+ }
+
+ mod_phy_reg(pi, 0xa2, ((0xf << 0) | (0xf << 4)), txrx_chain);
+
+ if (CoreActv_override) {
+ pi->nphy_perical = PHY_PERICAL_DISABLE;
+ or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override);
+ } else {
+ pi->nphy_perical = PHY_PERICAL_MPHASE;
+ and_phy_reg(pi, 0xa1, ~NPHY_RfseqMode_CoreActv_override);
+ }
+}
+
+void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask)
+{
+ u16 regval;
+ u16 tbl_buf[16];
+ uint i;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+ u16 tbl_opcode;
+ bool suspend;
+
+ pi->sh->phyrxchain = rxcore_bitmask;
+
+ if (!pi->sh->clk)
return;
- and_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL,
- ~(RADIO_2055_CAL_LPO_ENABLE));
+ suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!suspend)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
- wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
- write_radio_reg(pi, RADIO_2055_CORE1_RXBB_LPF, 9);
- write_radio_reg(pi, RADIO_2055_CORE2_RXBB_LPF, 9);
+ regval = read_phy_reg(pi, 0xa2);
+ regval &= ~(0xf << 4);
+ regval |= ((u16) (rxcore_bitmask & 0x3)) << 4;
+ write_phy_reg(pi, 0xa2, regval);
- write_radio_reg(pi, RADIO_2055_CORE1_RXBB_MIDAC_HIPAS, 0x83);
- write_radio_reg(pi, RADIO_2055_CORE2_RXBB_MIDAC_HIPAS, 0x83);
+ if ((rxcore_bitmask & 0x3) != 0x3) {
- mod_radio_reg(pi, RADIO_2055_CORE1_LNA_GAINBST,
- RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE);
- mod_radio_reg(pi, RADIO_2055_CORE2_LNA_GAINBST,
- RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE);
- if (pi->nphy_gain_boost) {
- and_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1,
- ~(RADIO_2055_GAINBST_DISABLE));
- and_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1,
- ~(RADIO_2055_GAINBST_DISABLE));
+ write_phy_reg(pi, 0x20e, 1);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->rx2tx_biasentry == -1) {
+ wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ ARRAY_SIZE(tbl_buf), 80,
+ 16, tbl_buf);
+
+ for (i = 0; i < ARRAY_SIZE(tbl_buf); i++) {
+ if (tbl_buf[i] ==
+ NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS) {
+ pi->rx2tx_biasentry = (u8) i;
+ tbl_opcode =
+ NPHY_REV3_RFSEQ_CMD_NOP;
+ wlc_phy_table_write_nphy(
+ pi,
+ NPHY_TBL_ID_RFSEQ,
+ 1, i,
+ 16,
+ &tbl_opcode);
+ break;
+ } else if (tbl_buf[i] ==
+ NPHY_REV3_RFSEQ_CMD_END)
+ break;
+ }
+ }
+ }
} else {
- or_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1,
- RADIO_2055_GAINBST_DISABLE);
- or_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1,
- RADIO_2055_GAINBST_DISABLE);
+
+ write_phy_reg(pi, 0x20e, 30);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (pi->rx2tx_biasentry != -1) {
+ tbl_opcode = NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ,
+ 1, pi->rx2tx_biasentry,
+ 16, &tbl_opcode);
+ pi->rx2tx_biasentry = -1;
+ }
+ }
}
- udelay(2);
+ wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ if (!suspend)
+ wlapi_enable_mac(pi->sh->physhim);
+}
+
+u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih)
+{
+ u16 regval, rxen_bits;
+ struct brcms_phy *pi = (struct brcms_phy *) pih;
+
+ regval = read_phy_reg(pi, 0xa2);
+ rxen_bits = (regval >> 4) & 0xf;
+
+ return (u8) rxen_bits;
+}
+
+bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi)
+{
+ return PHY_IPA(pi);
+}
+
+void wlc_phy_cal_init_nphy(struct brcms_phy *pi)
+{
}
static void wlc_phy_radio_preinit_205x(struct brcms_phy *pi)
@@ -17442,11 +20004,257 @@ static void wlc_phy_radio_preinit_205x(struct brcms_phy *pi)
}
+static void wlc_phy_radio_init_2057(struct brcms_phy *pi)
+{
+ struct radio_20xx_regs *regs_2057_ptr = NULL;
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+ regs_2057_ptr = regs_2057_rev4;
+ } else if (NREV_IS(pi->pubpi.phy_rev, 8)
+ || NREV_IS(pi->pubpi.phy_rev, 9)) {
+ switch (pi->pubpi.radiorev) {
+ case 5:
+
+ if (pi->pubpi.radiover == 0x0)
+ regs_2057_ptr = regs_2057_rev5;
+ else if (pi->pubpi.radiover == 0x1)
+ regs_2057_ptr = regs_2057_rev5v1;
+ else
+ break;
+
+ case 7:
+
+ regs_2057_ptr = regs_2057_rev7;
+ break;
+
+ case 8:
+
+ regs_2057_ptr = regs_2057_rev8;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ wlc_phy_init_radio_regs_allbands(pi, regs_2057_ptr);
+}
+
+static u16 wlc_phy_radio205x_rcal(struct brcms_phy *pi)
+{
+ u16 rcal_reg = 0;
+ int i;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if (pi->pubpi.radiorev == 5) {
+
+ and_phy_reg(pi, 0x342, ~(0x1 << 1));
+
+ udelay(10);
+
+ mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x1);
+ mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2,
+ 0x1);
+ }
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x1);
+
+ udelay(10);
+
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x3, 0x3);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS);
+ if (rcal_reg & 0x1)
+ break;
+
+ udelay(100);
+ }
+
+ if (WARN(i == MAX_205x_RCAL_WAITLOOPS,
+ "HW error: radio calib2"))
+ return 0;
+
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x2, 0x0);
+
+ rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS) & 0x3e;
+
+ mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x0);
+ if (pi->pubpi.radiorev == 5) {
+
+ mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x0);
+ mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2,
+ 0x0);
+ }
+
+ if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) {
+
+ mod_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x3c,
+ rcal_reg);
+ mod_radio_reg(pi, RADIO_2057_BANDGAP_RCAL_TRIM, 0xf0,
+ rcal_reg << 2);
+ }
+
+ } else if (NREV_IS(pi->pubpi.phy_rev, 3)) {
+ u16 savereg;
+
+ savereg =
+ read_radio_reg(
+ pi,
+ RADIO_2056_SYN_PLL_MAST2 |
+ RADIO_2056_SYN);
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN,
+ savereg | 0x7);
+ udelay(10);
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x1);
+ udelay(10);
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x9);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rcal_reg = read_radio_reg(
+ pi,
+ RADIO_2056_SYN_RCAL_CODE_OUT |
+ RADIO_2056_SYN);
+ if (rcal_reg & 0x80)
+ break;
+
+ udelay(100);
+ }
+
+ if (WARN(i == MAX_205x_RCAL_WAITLOOPS,
+ "HW error: radio calib3"))
+ return 0;
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x1);
+
+ rcal_reg =
+ read_radio_reg(pi,
+ RADIO_2056_SYN_RCAL_CODE_OUT |
+ RADIO_2056_SYN);
+
+ write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
+ 0x0);
+
+ write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN,
+ savereg);
+
+ return rcal_reg & 0x1f;
+ }
+ return rcal_reg & 0x3e;
+}
+
+static u16 wlc_phy_radio2057_rccal(struct brcms_phy *pi)
+{
+ u16 rccal_valid;
+ int i;
+ bool chip43226_6362A0;
+
+ chip43226_6362A0 = ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6));
+
+ rccal_valid = 0;
+ if (chip43226_6362A0) {
+ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x61);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xc0);
+ } else {
+ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x61);
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xe9);
+ }
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
+ if (rccal_valid & 0x2)
+ break;
+
+ udelay(500);
+ }
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
+
+ rccal_valid = 0;
+ if (chip43226_6362A0) {
+ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x69);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0);
+ } else {
+ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x69);
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xd5);
+ }
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
+ if (rccal_valid & 0x2)
+ break;
+
+ udelay(500);
+ }
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
+
+ rccal_valid = 0;
+ if (chip43226_6362A0) {
+ write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x73);
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x28);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0);
+ } else {
+ write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x73);
+ write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
+ write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0x99);
+ }
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
+
+ for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
+ rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
+ if (rccal_valid & 0x2)
+ break;
+
+ udelay(500);
+ }
+
+ if (WARN(!(rccal_valid & 0x2), "HW error: radio calib4"))
+ return 0;
+
+ write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
+
+ return rccal_valid;
+}
+
+static void wlc_phy_radio_postinit_2057(struct brcms_phy *pi)
+{
+
+ mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1);
+
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x78);
+ mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x80);
+ mdelay(2);
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x0);
+ mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x0);
+
+ if (pi->phy_init_por) {
+ wlc_phy_radio205x_rcal(pi);
+ wlc_phy_radio2057_rccal(pi);
+ }
+
+ mod_radio_reg(pi, RADIO_2057_RFPLL_MASTER, 0x8, 0x0);
+}
+
static void wlc_phy_radio_init_2056(struct brcms_phy *pi)
{
- struct radio_regs *regs_SYN_2056_ptr = NULL;
- struct radio_regs *regs_TX_2056_ptr = NULL;
- struct radio_regs *regs_RX_2056_ptr = NULL;
+ const struct radio_regs *regs_SYN_2056_ptr = NULL;
+ const struct radio_regs *regs_TX_2056_ptr = NULL;
+ const struct radio_regs *regs_RX_2056_ptr = NULL;
if (NREV_IS(pi->pubpi.phy_rev, 3)) {
regs_SYN_2056_ptr = regs_SYN_2056;
@@ -17515,92 +20323,190 @@ static void wlc_phy_radio_postinit_2056(struct brcms_phy *pi)
mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x0);
if ((pi->sh->boardflags2 & BFL2_LEGACY)
- || (pi->sh->boardflags2 & BFL2_XTALBUFOUTEN)) {
-
+ || (pi->sh->boardflags2 & BFL2_XTALBUFOUTEN))
mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xf4, 0x0);
- } else {
-
+ else
mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xfc, 0x0);
- }
mod_radio_reg(pi, RADIO_2056_SYN_RCCAL_CTRL0, 0x1, 0x0);
- if (pi->phy_init_por) {
+ if (pi->phy_init_por)
wlc_phy_radio205x_rcal(pi);
- }
}
-static void wlc_phy_radio_init_2057(struct brcms_phy *pi)
+static void wlc_phy_radio_preinit_2055(struct brcms_phy *pi)
{
- struct radio_20xx_regs *regs_2057_ptr = NULL;
- if (NREV_IS(pi->pubpi.phy_rev, 7)) {
+ and_phy_reg(pi, 0x78, ~RFCC_POR_FORCE);
+ or_phy_reg(pi, 0x78, RFCC_CHIP0_PU | RFCC_OE_POR_FORCE);
- regs_2057_ptr = regs_2057_rev4;
- } else if (NREV_IS(pi->pubpi.phy_rev, 8)
- || NREV_IS(pi->pubpi.phy_rev, 9)) {
- switch (pi->pubpi.radiorev) {
- case 5:
+ or_phy_reg(pi, 0x78, RFCC_POR_FORCE);
+}
- if (pi->pubpi.radiover == 0x0) {
+static void wlc_phy_radio_init_2055(struct brcms_phy *pi)
+{
+ wlc_phy_init_radio_regs(pi, regs_2055, RADIO_DEFAULT_CORE);
+}
- regs_2057_ptr = regs_2057_rev5;
+static void wlc_phy_radio_postinit_2055(struct brcms_phy *pi)
+{
- } else if (pi->pubpi.radiover == 0x1) {
+ and_radio_reg(pi, RADIO_2055_MASTER_CNTRL1,
+ ~(RADIO_2055_JTAGCTRL_MASK | RADIO_2055_JTAGSYNC_MASK));
- regs_2057_ptr = regs_2057_rev5v1;
- } else {
- break;
- }
+ if (((pi->sh->sromrev >= 4)
+ && !(pi->sh->boardflags2 & BFL2_RXBB_INT_REG_DIS))
+ || ((pi->sh->sromrev < 4))) {
+ and_radio_reg(pi, RADIO_2055_CORE1_RXBB_REGULATOR, 0x7F);
+ and_radio_reg(pi, RADIO_2055_CORE2_RXBB_REGULATOR, 0x7F);
+ }
- case 7:
+ mod_radio_reg(pi, RADIO_2055_RRCCAL_N_OPT_SEL, 0x3F, 0x2C);
+ write_radio_reg(pi, RADIO_2055_CAL_MISC, 0x3C);
- regs_2057_ptr = regs_2057_rev7;
- break;
+ and_radio_reg(pi, RADIO_2055_CAL_MISC,
+ ~(RADIO_2055_RRCAL_START | RADIO_2055_RRCAL_RST_N));
- case 8:
+ or_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, RADIO_2055_CAL_LPO_ENABLE);
- regs_2057_ptr = regs_2057_rev8;
- break;
+ or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_RST_N);
- default:
- break;
- }
+ udelay(1000);
+
+ or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_START);
+
+ SPINWAIT(((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) &
+ RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE), 2000);
+
+ if (WARN((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) &
+ RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE,
+ "HW error: radio calibration1\n"))
+ return;
+
+ and_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL,
+ ~(RADIO_2055_CAL_LPO_ENABLE));
+
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_RXBB_LPF, 9);
+ write_radio_reg(pi, RADIO_2055_CORE2_RXBB_LPF, 9);
+
+ write_radio_reg(pi, RADIO_2055_CORE1_RXBB_MIDAC_HIPAS, 0x83);
+ write_radio_reg(pi, RADIO_2055_CORE2_RXBB_MIDAC_HIPAS, 0x83);
+
+ mod_radio_reg(pi, RADIO_2055_CORE1_LNA_GAINBST,
+ RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE);
+ mod_radio_reg(pi, RADIO_2055_CORE2_LNA_GAINBST,
+ RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE);
+ if (pi->nphy_gain_boost) {
+ and_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1,
+ ~(RADIO_2055_GAINBST_DISABLE));
+ and_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1,
+ ~(RADIO_2055_GAINBST_DISABLE));
+ } else {
+ or_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1,
+ RADIO_2055_GAINBST_DISABLE);
+ or_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1,
+ RADIO_2055_GAINBST_DISABLE);
}
- wlc_phy_init_radio_regs_allbands(pi, regs_2057_ptr);
+ udelay(2);
}
-static void wlc_phy_radio_postinit_2057(struct brcms_phy *pi)
+void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on)
{
+ if (on) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (!pi->radio_is_on) {
+ wlc_phy_radio_preinit_205x(pi);
+ wlc_phy_radio_init_2057(pi);
+ wlc_phy_radio_postinit_2057(pi);
+ }
- mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1);
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi,
+ pi->radio_chanspec);
+ } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ wlc_phy_radio_preinit_205x(pi);
+ wlc_phy_radio_init_2056(pi);
+ wlc_phy_radio_postinit_2056(pi);
- mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x78);
- mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x80);
- mdelay(2);
- mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x0);
- mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x0);
+ wlc_phy_chanspec_set((struct brcms_phy_pub *) pi,
+ pi->radio_chanspec);
+ } else {
+ wlc_phy_radio_preinit_2055(pi);
+ wlc_phy_radio_init_2055(pi);
+ wlc_phy_radio_postinit_2055(pi);
+ }
- if (pi->phy_init_por) {
- wlc_phy_radio205x_rcal(pi);
- wlc_phy_radio2057_rccal(pi);
- }
+ pi->radio_is_on = true;
- mod_radio_reg(pi, RADIO_2057_RFPLL_MASTER, 0x8, 0x0);
+ } else {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3)
+ && NREV_LT(pi->pubpi.phy_rev, 7)) {
+ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
+ mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x0);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADA_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADG_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAA_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAG_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+ mod_radio_reg(pi,
+ RADIO_2056_TX_MIXA_BOOST_TUNE |
+ RADIO_2056_TX0, 0xf0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_MIXG_BOOST_TUNE |
+ RADIO_2056_TX0, 0);
+
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADA_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PADG_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAA_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_PGAG_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+ mod_radio_reg(pi,
+ RADIO_2056_TX_MIXA_BOOST_TUNE |
+ RADIO_2056_TX1, 0xf0, 0);
+ write_radio_reg(pi,
+ RADIO_2056_TX_MIXG_BOOST_TUNE |
+ RADIO_2056_TX1, 0);
+
+ pi->radio_is_on = false;
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 8)) {
+ and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU);
+ pi->radio_is_on = false;
+ }
+
+ }
}
static bool
wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
- struct chan_info_nphy_radio2057 **t0,
- struct chan_info_nphy_radio205x **t1,
- struct chan_info_nphy_radio2057_rev5 **t2,
- struct chan_info_nphy_2055 **t3)
+ const struct chan_info_nphy_radio2057 **t0,
+ const struct chan_info_nphy_radio205x **t1,
+ const struct chan_info_nphy_radio2057_rev5 **t2,
+ const struct chan_info_nphy_2055 **t3)
{
uint i;
- struct chan_info_nphy_radio2057 *chan_info_tbl_p_0 = NULL;
- struct chan_info_nphy_radio205x *chan_info_tbl_p_1 = NULL;
- struct chan_info_nphy_radio2057_rev5 *chan_info_tbl_p_2 = NULL;
+ const struct chan_info_nphy_radio2057 *chan_info_tbl_p_0 = NULL;
+ const struct chan_info_nphy_radio205x *chan_info_tbl_p_1 = NULL;
+ const struct chan_info_nphy_radio2057_rev5 *chan_info_tbl_p_2 = NULL;
u32 tbl_len = 0;
int freq = 0;
@@ -17621,40 +20527,35 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
if (pi->pubpi.radiover == 0x0) {
chan_info_tbl_p_2 =
- chan_info_nphyrev8_2057_rev5;
- tbl_len =
- ARRAY_SIZE
- (chan_info_nphyrev8_2057_rev5);
+ chan_info_nphyrev8_2057_rev5;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev8_2057_rev5);
} else if (pi->pubpi.radiover == 0x1) {
chan_info_tbl_p_2 =
- chan_info_nphyrev9_2057_rev5v1;
- tbl_len =
- ARRAY_SIZE
- (chan_info_nphyrev9_2057_rev5v1);
+ chan_info_nphyrev9_2057_rev5v1;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev9_2057_rev5v1);
}
break;
case 7:
chan_info_tbl_p_0 =
- chan_info_nphyrev8_2057_rev7;
- tbl_len =
- ARRAY_SIZE(chan_info_nphyrev8_2057_rev7);
+ chan_info_nphyrev8_2057_rev7;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev8_2057_rev7);
break;
case 8:
chan_info_tbl_p_0 =
- chan_info_nphyrev8_2057_rev8;
- tbl_len =
- ARRAY_SIZE(chan_info_nphyrev8_2057_rev8);
+ chan_info_nphyrev8_2057_rev8;
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev8_2057_rev8);
break;
default:
- if (NORADIO_ENAB(pi->pubpi)) {
- goto fail;
- }
break;
}
} else if (NREV_IS(pi->pubpi.phy_rev, 16)) {
@@ -17677,9 +20578,9 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
}
}
- if (i >= tbl_len) {
+ if (i >= tbl_len)
goto fail;
- }
+
if (pi->pubpi.radiorev == 5) {
*t2 = &chan_info_tbl_p_2[i];
freq = chan_info_tbl_p_2[i].freq;
@@ -17710,7 +20611,7 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
case 9:
chan_info_tbl_p_1 = chan_info_nphyrev5n6_2056v7;
tbl_len =
- ARRAY_SIZE(chan_info_nphyrev5n6_2056v7);
+ ARRAY_SIZE(chan_info_nphyrev5n6_2056v7);
break;
case 8:
chan_info_tbl_p_1 = chan_info_nphyrev6_2056v8;
@@ -17718,12 +20619,10 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
break;
case 11:
chan_info_tbl_p_1 = chan_info_nphyrev6_2056v11;
- tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v11);
+ tbl_len = ARRAY_SIZE(
+ chan_info_nphyrev6_2056v11);
break;
default:
- if (NORADIO_ENAB(pi->pubpi)) {
- goto fail;
- }
break;
}
}
@@ -17733,9 +20632,9 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
break;
}
- if (i >= tbl_len) {
+ if (i >= tbl_len)
goto fail;
- }
+
*t1 = &chan_info_tbl_p_1[i];
freq = chan_info_tbl_p_1[i].freq;
@@ -17744,9 +20643,9 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
if (chan_info_nphy_2055[i].chan == channel)
break;
- if (i >= ARRAY_SIZE(chan_info_nphy_2055)) {
+ if (i >= ARRAY_SIZE(chan_info_nphy_2055))
goto fail;
- }
+
*t3 = &chan_info_nphy_2055[i];
freq = chan_info_nphy_2055[i].freq;
}
@@ -17754,7 +20653,7 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
*f = freq;
return true;
- fail:
+fail:
*f = WL_CHAN_FREQ_RANGE_2G;
return false;
}
@@ -17762,13 +20661,10 @@ wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f,
u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint channel)
{
int freq;
- struct chan_info_nphy_radio2057 *t0 = NULL;
- struct chan_info_nphy_radio205x *t1 = NULL;
- struct chan_info_nphy_radio2057_rev5 *t2 = NULL;
- struct chan_info_nphy_2055 *t3 = NULL;
-
- if (NORADIO_ENAB(pi->pubpi))
- return WL_CHAN_FREQ_RANGE_2G;
+ const struct chan_info_nphy_radio2057 *t0 = NULL;
+ const struct chan_info_nphy_radio205x *t1 = NULL;
+ const struct chan_info_nphy_radio2057_rev5 *t2 = NULL;
+ const struct chan_info_nphy_2055 *t3 = NULL;
if (channel == 0)
channel = CHSPEC_CHANNEL(pi->radio_chanspec);
@@ -17778,18 +20674,17 @@ u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint channel)
if (CHSPEC_IS2G(pi->radio_chanspec))
return WL_CHAN_FREQ_RANGE_2G;
- if ((freq >= BASE_LOW_5G_CHAN) && (freq < BASE_MID_5G_CHAN)) {
+ if ((freq >= BASE_LOW_5G_CHAN) && (freq < BASE_MID_5G_CHAN))
return WL_CHAN_FREQ_RANGE_5GL;
- } else if ((freq >= BASE_MID_5G_CHAN) && (freq < BASE_HIGH_5G_CHAN)) {
+ else if ((freq >= BASE_MID_5G_CHAN) && (freq < BASE_HIGH_5G_CHAN))
return WL_CHAN_FREQ_RANGE_5GM;
- } else {
+ else
return WL_CHAN_FREQ_RANGE_5GH;
- }
}
static void
wlc_phy_chanspec_radio2055_setup(struct brcms_phy *pi,
- struct chan_info_nphy_2055 *ci)
+ const struct chan_info_nphy_2055 *ci)
{
write_radio_reg(pi, RADIO_2055_PLL_REF, ci->RF_pll_ref);
@@ -17854,7 +20749,7 @@ static void
wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi,
const struct chan_info_nphy_radio205x *ci)
{
- struct radio_regs *regs_SYN_2056_ptr = NULL;
+ const struct radio_regs *regs_SYN_2056_ptr = NULL;
write_radio_reg(pi,
RADIO_2056_SYN_PLL_VCOCAL1 | RADIO_2056_SYN,
@@ -17960,15 +20855,14 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi,
break;
}
}
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 |
RADIO_2056_SYN,
(u16) regs_SYN_2056_ptr[0x49 - 2].init_g);
- } else {
+ else
write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 |
RADIO_2056_SYN,
(u16) regs_SYN_2056_ptr[0x49 - 2].init_a);
- }
if (pi->sh->boardflags2 & BFL2_GPLL_WAR) {
if (CHSPEC_IS2G(pi->radio_chanspec)) {
@@ -18069,7 +20963,8 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi,
mixg_boost_tune);
} else {
- bias = IS40MHZ(pi) ? 0x40 : 0x20;
+ bias = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 0x40 : 0x20;
WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
INTPAG_IMAIN_STAT, bias);
@@ -18116,11 +21011,11 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi,
paa_boost_tune = 0x0;
pada_boost_tune = 0x77;
- if (freq != 5825) {
+ if (freq != 5825)
pgaa_boost_tune = -(int)(freq - 18) / 36 + 168;
- } else {
+ else
pgaa_boost_tune = 6;
- }
+
mixa_boost_tune = 0xf;
}
@@ -18146,9 +21041,8 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi,
if ((pi->sh->chip == BCM43224_CHIP_ID) ||
(pi->sh->chip == BCM43225_CHIP_ID)) {
- if (pi->sh->chippkg == BCM43224_FAB_SMIC) {
+ if (pi->sh->chippkg == BCM43224_FAB_SMIC)
cascbias = 0x35;
- }
}
pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias;
@@ -18186,117 +21080,12 @@ void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi)
udelay(300);
}
-#define MAX_205x_RCAL_WAITLOOPS 10000
-
-static u16 wlc_phy_radio205x_rcal(struct brcms_phy *pi)
-{
- u16 rcal_reg = 0;
- int i;
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- if (pi->pubpi.radiorev == 5) {
-
- and_phy_reg(pi, 0x342, ~(0x1 << 1));
-
- udelay(10);
-
- mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x1);
- mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2,
- 0x1);
- }
- mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x1);
-
- udelay(10);
-
- mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x3, 0x3);
-
- for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
- rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS);
- if (rcal_reg & 0x1) {
- break;
- }
- udelay(100);
- }
-
- if (WARN(i == MAX_205x_RCAL_WAITLOOPS,
- "HW error: radio calib2"))
- return 0;
-
- mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x2, 0x0);
-
- rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS) & 0x3e;
-
- mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x0);
- if (pi->pubpi.radiorev == 5) {
-
- mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x0);
- mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2,
- 0x0);
- }
-
- if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) {
-
- mod_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x3c,
- rcal_reg);
- mod_radio_reg(pi, RADIO_2057_BANDGAP_RCAL_TRIM, 0xf0,
- rcal_reg << 2);
- }
-
- } else if (NREV_IS(pi->pubpi.phy_rev, 3)) {
- u16 savereg;
-
- savereg =
- read_radio_reg(pi,
- RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN);
- write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN,
- savereg | 0x7);
- udelay(10);
-
- write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
- 0x1);
- udelay(10);
-
- write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
- 0x9);
-
- for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
- rcal_reg = read_radio_reg(pi,
- RADIO_2056_SYN_RCAL_CODE_OUT |
- RADIO_2056_SYN);
- if (rcal_reg & 0x80) {
- break;
- }
- udelay(100);
- }
-
- if (WARN(i == MAX_205x_RCAL_WAITLOOPS,
- "HW error: radio calib3"))
- return 0;
-
- write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
- 0x1);
-
- rcal_reg =
- read_radio_reg(pi,
- RADIO_2056_SYN_RCAL_CODE_OUT |
- RADIO_2056_SYN);
-
- write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN,
- 0x0);
-
- write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN,
- savereg);
-
- return rcal_reg & 0x1f;
- }
- return rcal_reg & 0x3e;
-}
-
static void
-wlc_phy_chanspec_radio2057_setup(struct brcms_phy *pi,
- const struct chan_info_nphy_radio2057 *ci,
- const struct chan_info_nphy_radio2057_rev5 *ci2)
+wlc_phy_chanspec_radio2057_setup(
+ struct brcms_phy *pi,
+ const struct chan_info_nphy_radio2057 *ci,
+ const struct chan_info_nphy_radio2057_rev5 *
+ ci2)
{
int coreNum;
u16 txmix2g_tune_boost_pu = 0;
@@ -18455,9 +21244,8 @@ wlc_phy_chanspec_radio2057_setup(struct brcms_phy *pi,
if (CHSPEC_IS2G(pi->radio_chanspec)) {
if (PHY_IPA(pi)) {
- if (pi->pubpi.radiorev == 3) {
+ if (pi->pubpi.radiorev == 3)
txmix2g_tune_boost_pu = 0x6b;
- }
if (pi->pubpi.radiorev == 5)
pad2g_tune_pus = 0x73;
@@ -18489,430 +21277,8 @@ wlc_phy_chanspec_radio2057_setup(struct brcms_phy *pi,
wlc_phy_radio205x_vcocal_nphy(pi);
}
-static u16 wlc_phy_radio2057_rccal(struct brcms_phy *pi)
-{
- u16 rccal_valid;
- int i;
- bool chip43226_6362A0;
-
- chip43226_6362A0 = ((pi->pubpi.radiorev == 3)
- || (pi->pubpi.radiorev == 4)
- || (pi->pubpi.radiorev == 6));
-
- rccal_valid = 0;
- if (chip43226_6362A0) {
- write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x61);
- write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xc0);
- } else {
- write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x61);
-
- write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xe9);
- }
- write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
- write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
-
- for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
- rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
- if (rccal_valid & 0x2) {
- break;
- }
- udelay(500);
- }
-
- write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
-
- rccal_valid = 0;
- if (chip43226_6362A0) {
- write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x69);
- write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0);
- } else {
- write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x69);
-
- write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xd5);
- }
- write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
- write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
-
- for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
- rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
- if (rccal_valid & 0x2) {
- break;
- }
- udelay(500);
- }
-
- write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
-
- rccal_valid = 0;
- if (chip43226_6362A0) {
- write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x73);
-
- write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x28);
- write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0);
- } else {
- write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x73);
- write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e);
- write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0x99);
- }
- write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55);
-
- for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) {
- rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP);
- if (rccal_valid & 0x2) {
- break;
- }
- udelay(500);
- }
-
- if (WARN(!(rccal_valid & 0x2), "HW error: radio calib4"))
- return 0;
-
- write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15);
-
- return rccal_valid;
-}
-
-static void
-wlc_phy_adjust_rx_analpfbw_nphy(struct brcms_phy *pi, u16 reduction_factr)
-{
- if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
- if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) &&
- CHSPEC_IS40(pi->radio_chanspec)) {
- if (!pi->nphy_anarxlpf_adjusted) {
- write_radio_reg(pi,
- (RADIO_2056_RX_RXLPF_RCCAL_LPC |
- RADIO_2056_RX0),
- ((pi->nphy_rccal_value +
- reduction_factr) | 0x80));
-
- pi->nphy_anarxlpf_adjusted = true;
- }
- } else {
- if (pi->nphy_anarxlpf_adjusted) {
- write_radio_reg(pi,
- (RADIO_2056_RX_RXLPF_RCCAL_LPC |
- RADIO_2056_RX0),
- (pi->nphy_rccal_value | 0x80));
-
- pi->nphy_anarxlpf_adjusted = false;
- }
- }
- }
-}
-
-static void
-wlc_phy_adjust_min_noisevar_nphy(struct brcms_phy *pi, int ntones,
- int *tone_id_buf, u32 *noise_var_buf)
-{
- int i;
- u32 offset;
- int tone_id;
- int tbllen =
- CHSPEC_IS40(pi->
- radio_chanspec) ? NPHY_NOISEVAR_TBLLEN40 :
- NPHY_NOISEVAR_TBLLEN20;
-
- if (pi->nphy_noisevars_adjusted) {
- for (i = 0; i < pi->nphy_saved_noisevars.bufcount; i++) {
- tone_id = pi->nphy_saved_noisevars.tone_id[i];
- offset = (tone_id >= 0) ?
- ((tone_id * 2) + 1) : (tbllen + (tone_id * 2) + 1);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
- offset, 32,
- (void *)&pi->
- nphy_saved_noisevars.
- min_noise_vars[i]);
- }
-
- pi->nphy_saved_noisevars.bufcount = 0;
- pi->nphy_noisevars_adjusted = false;
- }
-
- if ((noise_var_buf != NULL) && (tone_id_buf != NULL)) {
- pi->nphy_saved_noisevars.bufcount = 0;
-
- for (i = 0; i < ntones; i++) {
- tone_id = tone_id_buf[i];
- offset = (tone_id >= 0) ?
- ((tone_id * 2) + 1) : (tbllen + (tone_id * 2) + 1);
- pi->nphy_saved_noisevars.tone_id[i] = tone_id;
- wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
- offset, 32,
- &pi->nphy_saved_noisevars.
- min_noise_vars[i]);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1,
- offset, 32,
- (void *)&noise_var_buf[i]);
- pi->nphy_saved_noisevars.bufcount++;
- }
-
- pi->nphy_noisevars_adjusted = true;
- }
-}
-
-static void wlc_phy_adjust_crsminpwr_nphy(struct brcms_phy *pi, u8 minpwr)
-{
- u16 regval;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) &&
- CHSPEC_IS40(pi->radio_chanspec)) {
- if (!pi->nphy_crsminpwr_adjusted) {
- regval = read_phy_reg(pi, 0x27d);
- pi->nphy_crsminpwr[0] = regval & 0xff;
- regval &= 0xff00;
- regval |= (u16) minpwr;
- write_phy_reg(pi, 0x27d, regval);
-
- regval = read_phy_reg(pi, 0x280);
- pi->nphy_crsminpwr[1] = regval & 0xff;
- regval &= 0xff00;
- regval |= (u16) minpwr;
- write_phy_reg(pi, 0x280, regval);
-
- regval = read_phy_reg(pi, 0x283);
- pi->nphy_crsminpwr[2] = regval & 0xff;
- regval &= 0xff00;
- regval |= (u16) minpwr;
- write_phy_reg(pi, 0x283, regval);
-
- pi->nphy_crsminpwr_adjusted = true;
- }
- } else {
- if (pi->nphy_crsminpwr_adjusted) {
- regval = read_phy_reg(pi, 0x27d);
- regval &= 0xff00;
- regval |= pi->nphy_crsminpwr[0];
- write_phy_reg(pi, 0x27d, regval);
-
- regval = read_phy_reg(pi, 0x280);
- regval &= 0xff00;
- regval |= pi->nphy_crsminpwr[1];
- write_phy_reg(pi, 0x280, regval);
-
- regval = read_phy_reg(pi, 0x283);
- regval &= 0xff00;
- regval |= pi->nphy_crsminpwr[2];
- write_phy_reg(pi, 0x283, regval);
-
- pi->nphy_crsminpwr_adjusted = false;
- }
- }
- }
-}
-
-static void wlc_phy_txlpfbw_nphy(struct brcms_phy *pi)
-{
- u8 tx_lpf_bw = 0;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- tx_lpf_bw = 3;
- } else {
- tx_lpf_bw = 1;
- }
-
- if (PHY_IPA(pi)) {
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- tx_lpf_bw = 5;
- } else {
- tx_lpf_bw = 4;
- }
- }
- write_phy_reg(pi, 0xe8,
- (tx_lpf_bw << 0) |
- (tx_lpf_bw << 3) |
- (tx_lpf_bw << 6) | (tx_lpf_bw << 9));
-
- if (PHY_IPA(pi)) {
-
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- tx_lpf_bw = 4;
- } else {
- tx_lpf_bw = 1;
- }
-
- write_phy_reg(pi, 0xe9,
- (tx_lpf_bw << 0) |
- (tx_lpf_bw << 3) |
- (tx_lpf_bw << 6) | (tx_lpf_bw << 9));
- }
- }
-}
-
-static void wlc_phy_spurwar_nphy(struct brcms_phy *pi)
-{
- u16 cur_channel = 0;
- int nphy_adj_tone_id_buf[] = { 57, 58 };
- u32 nphy_adj_noise_var_buf[] = { 0x3ff, 0x3ff };
- bool isAdjustNoiseVar = false;
- uint numTonesAdjust = 0;
- u32 tempval = 0;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- cur_channel = CHSPEC_CHANNEL(pi->radio_chanspec);
-
- if (pi->nphy_gband_spurwar_en) {
-
- wlc_phy_adjust_rx_analpfbw_nphy(pi,
- NPHY_ANARXLPFBW_REDUCTIONFACT);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if ((cur_channel == 11)
- && CHSPEC_IS40(pi->radio_chanspec)) {
-
- wlc_phy_adjust_min_noisevar_nphy(pi, 2,
- nphy_adj_tone_id_buf,
- nphy_adj_noise_var_buf);
- } else {
-
- wlc_phy_adjust_min_noisevar_nphy(pi, 0,
- NULL,
- NULL);
- }
- }
- wlc_phy_adjust_crsminpwr_nphy(pi,
- NPHY_ADJUSTED_MINCRSPOWER);
- }
-
- if ((pi->nphy_gband_spurwar2_en)
- && CHSPEC_IS2G(pi->radio_chanspec)) {
-
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- switch (cur_channel) {
- case 3:
- nphy_adj_tone_id_buf[0] = 57;
- nphy_adj_tone_id_buf[1] = 58;
- nphy_adj_noise_var_buf[0] = 0x22f;
- nphy_adj_noise_var_buf[1] = 0x25f;
- isAdjustNoiseVar = true;
- break;
- case 4:
- nphy_adj_tone_id_buf[0] = 41;
- nphy_adj_tone_id_buf[1] = 42;
- nphy_adj_noise_var_buf[0] = 0x22f;
- nphy_adj_noise_var_buf[1] = 0x25f;
- isAdjustNoiseVar = true;
- break;
- case 5:
- nphy_adj_tone_id_buf[0] = 25;
- nphy_adj_tone_id_buf[1] = 26;
- nphy_adj_noise_var_buf[0] = 0x24f;
- nphy_adj_noise_var_buf[1] = 0x25f;
- isAdjustNoiseVar = true;
- break;
- case 6:
- nphy_adj_tone_id_buf[0] = 9;
- nphy_adj_tone_id_buf[1] = 10;
- nphy_adj_noise_var_buf[0] = 0x22f;
- nphy_adj_noise_var_buf[1] = 0x24f;
- isAdjustNoiseVar = true;
- break;
- case 7:
- nphy_adj_tone_id_buf[0] = 121;
- nphy_adj_tone_id_buf[1] = 122;
- nphy_adj_noise_var_buf[0] = 0x18f;
- nphy_adj_noise_var_buf[1] = 0x24f;
- isAdjustNoiseVar = true;
- break;
- case 8:
- nphy_adj_tone_id_buf[0] = 105;
- nphy_adj_tone_id_buf[1] = 106;
- nphy_adj_noise_var_buf[0] = 0x22f;
- nphy_adj_noise_var_buf[1] = 0x25f;
- isAdjustNoiseVar = true;
- break;
- case 9:
- nphy_adj_tone_id_buf[0] = 89;
- nphy_adj_tone_id_buf[1] = 90;
- nphy_adj_noise_var_buf[0] = 0x22f;
- nphy_adj_noise_var_buf[1] = 0x24f;
- isAdjustNoiseVar = true;
- break;
- case 10:
- nphy_adj_tone_id_buf[0] = 73;
- nphy_adj_tone_id_buf[1] = 74;
- nphy_adj_noise_var_buf[0] = 0x22f;
- nphy_adj_noise_var_buf[1] = 0x24f;
- isAdjustNoiseVar = true;
- break;
- default:
- isAdjustNoiseVar = false;
- break;
- }
- }
-
- if (isAdjustNoiseVar) {
- numTonesAdjust = sizeof(nphy_adj_tone_id_buf) /
- sizeof(nphy_adj_tone_id_buf[0]);
-
- wlc_phy_adjust_min_noisevar_nphy(pi,
- numTonesAdjust,
- nphy_adj_tone_id_buf,
- nphy_adj_noise_var_buf);
-
- tempval = 0;
-
- } else {
-
- wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL,
- NULL);
- }
- }
-
- if ((pi->nphy_aband_spurwar_en) &&
- (CHSPEC_IS5G(pi->radio_chanspec))) {
- switch (cur_channel) {
- case 54:
- nphy_adj_tone_id_buf[0] = 32;
- nphy_adj_noise_var_buf[0] = 0x25f;
- break;
- case 38:
- case 102:
- case 118:
- nphy_adj_tone_id_buf[0] = 0;
- nphy_adj_noise_var_buf[0] = 0x0;
- break;
- case 134:
- nphy_adj_tone_id_buf[0] = 32;
- nphy_adj_noise_var_buf[0] = 0x21f;
- break;
- case 151:
- nphy_adj_tone_id_buf[0] = 16;
- nphy_adj_noise_var_buf[0] = 0x23f;
- break;
- case 153:
- case 161:
- nphy_adj_tone_id_buf[0] = 48;
- nphy_adj_noise_var_buf[0] = 0x23f;
- break;
- default:
- nphy_adj_tone_id_buf[0] = 0;
- nphy_adj_noise_var_buf[0] = 0x0;
- break;
- }
-
- if (nphy_adj_tone_id_buf[0]
- && nphy_adj_noise_var_buf[0]) {
- wlc_phy_adjust_min_noisevar_nphy(pi, 1,
- nphy_adj_tone_id_buf,
- nphy_adj_noise_var_buf);
- } else {
- wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL,
- NULL);
- }
- }
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
- }
-}
-
static void
-wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, chanspec_t chanspec,
+wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec,
const struct nphy_sfo_cfg *ci)
{
u16 val;
@@ -18964,14 +21330,11 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, chanspec_t chanspec,
and_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, ~0x840);
}
- if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) {
+ if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF)
wlc_phy_txpwr_fixpower_nphy(pi);
- }
-
- if (NREV_LT(pi->pubpi.phy_rev, 3)) {
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
wlc_phy_adjust_lnagaintbl_nphy(pi);
- }
wlc_phy_txlpfbw_nphy(pi);
@@ -18982,28 +21345,20 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, chanspec_t chanspec,
val = CHSPEC_CHANNEL(chanspec);
if (!CHSPEC_IS40(pi->radio_chanspec)) {
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if ((val == 13) || (val == 14) || (val == 153)) {
- spuravoid = 1;
- }
- } else {
-
- if (((val >= 5) && (val <= 8)) || (val == 13)
- || (val == 14)) {
+ if ((val == 13) || (val == 14) || (val == 153))
spuravoid = 1;
- }
+ } else if (((val >= 5) && (val <= 8)) || (val == 13)
+ || (val == 14)) {
+ spuravoid = 1;
}
+ } else if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (val == 54)
+ spuravoid = 1;
} else {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (val == 54) {
- spuravoid = 1;
- }
- } else {
-
- if (pi->nphy_aband_spurwar_en &&
- ((val == 38) || (val == 102)
- || (val == 118)))
- spuravoid = 1;
- }
+ if (pi->nphy_aband_spurwar_en &&
+ ((val == 38) || (val == 102)
+ || (val == 118)))
+ spuravoid = 1;
}
if (pi->phy_spuravoid == SPURAVOID_FORCEON)
@@ -19047,20 +21402,16 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, chanspec_t chanspec,
wlc_phy_spurwar_nphy(pi);
}
-void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, chanspec_t chanspec)
+void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec)
{
int freq;
- struct chan_info_nphy_radio2057 *t0 = NULL;
- struct chan_info_nphy_radio205x *t1 = NULL;
- struct chan_info_nphy_radio2057_rev5 *t2 = NULL;
- struct chan_info_nphy_2055 *t3 = NULL;
-
- if (NORADIO_ENAB(pi->pubpi)) {
- return;
- }
+ const struct chan_info_nphy_radio2057 *t0 = NULL;
+ const struct chan_info_nphy_radio205x *t1 = NULL;
+ const struct chan_info_nphy_radio2057_rev5 *t2 = NULL;
+ const struct chan_info_nphy_2055 *t3 = NULL;
if (!wlc_phy_chan2freq_nphy
- (pi, CHSPEC_CHANNEL(chanspec), &freq, &t0, &t1, &t2, &t3))
+ (pi, CHSPEC_CHANNEL(chanspec), &freq, &t0, &t1, &t2, &t3))
return;
wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec);
@@ -19071,15 +21422,13 @@ void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, chanspec_t chanspec)
if (CHSPEC_IS40(chanspec)) {
if (CHSPEC_SB_UPPER(chanspec)) {
or_phy_reg(pi, 0xa0, BPHY_BAND_SEL_UP20);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
or_phy_reg(pi, 0x310, PRIM_SEL_UP20);
- }
} else {
and_phy_reg(pi, 0xa0, ~BPHY_BAND_SEL_UP20);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
and_phy_reg(pi, 0x310,
(~PRIM_SEL_UP20 & 0xffff));
- }
}
}
@@ -19124,358 +21473,10 @@ void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, chanspec_t chanspec)
wlc_phy_chanspec_radio2055_setup(pi, t3);
wlc_phy_chanspec_nphy_setup(pi, chanspec,
- (const struct nphy_sfo_cfg *)&(t3->
- PHY_BW1a));
- }
-
-}
-
-static void wlc_phy_savecal_nphy(struct brcms_phy *pi)
-{
- void *tbl_ptr;
- int coreNum;
- u16 *txcal_radio_regs = NULL;
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
-
- wlc_phy_rx_iq_coeffs_nphy(pi, 0,
- &pi->calibration_cache.
- rxcal_coeffs_2G);
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- txcal_radio_regs =
- pi->calibration_cache.txcal_radio_regs_2G;
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
- pi->calibration_cache.txcal_radio_regs_2G[0] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_2G[1] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_2G[2] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX1);
- pi->calibration_cache.txcal_radio_regs_2G[3] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX1);
-
- pi->calibration_cache.txcal_radio_regs_2G[4] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_2G[5] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_2G[6] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX1);
- pi->calibration_cache.txcal_radio_regs_2G[7] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX1);
- } else {
- pi->calibration_cache.txcal_radio_regs_2G[0] =
- read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL);
- pi->calibration_cache.txcal_radio_regs_2G[1] =
- read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL);
- pi->calibration_cache.txcal_radio_regs_2G[2] =
- read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM);
- pi->calibration_cache.txcal_radio_regs_2G[3] =
- read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM);
- }
-
- pi->nphy_iqcal_chanspec_2G = pi->radio_chanspec;
- tbl_ptr = pi->calibration_cache.txcal_coeffs_2G;
- } else {
-
- wlc_phy_rx_iq_coeffs_nphy(pi, 0,
- &pi->calibration_cache.
- rxcal_coeffs_5G);
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- txcal_radio_regs =
- pi->calibration_cache.txcal_radio_regs_5G;
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
- pi->calibration_cache.txcal_radio_regs_5G[0] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_5G[1] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_5G[2] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX1);
- pi->calibration_cache.txcal_radio_regs_5G[3] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX1);
-
- pi->calibration_cache.txcal_radio_regs_5G[4] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_5G[5] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX0);
- pi->calibration_cache.txcal_radio_regs_5G[6] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX1);
- pi->calibration_cache.txcal_radio_regs_5G[7] =
- read_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX1);
- } else {
- pi->calibration_cache.txcal_radio_regs_5G[0] =
- read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL);
- pi->calibration_cache.txcal_radio_regs_5G[1] =
- read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL);
- pi->calibration_cache.txcal_radio_regs_5G[2] =
- read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM);
- pi->calibration_cache.txcal_radio_regs_5G[3] =
- read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM);
- }
-
- pi->nphy_iqcal_chanspec_5G = pi->radio_chanspec;
- tbl_ptr = pi->calibration_cache.txcal_coeffs_5G;
- }
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- for (coreNum = 0; coreNum <= 1; coreNum++) {
-
- txcal_radio_regs[2 * coreNum] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_FINE_I);
- txcal_radio_regs[2 * coreNum + 1] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_FINE_Q);
-
- txcal_radio_regs[2 * coreNum + 4] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_COARSE_I);
- txcal_radio_regs[2 * coreNum + 5] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_COARSE_Q);
- }
- }
-
- wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 8, 80, 16, tbl_ptr);
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-}
-
-static void wlc_phy_restorecal_nphy(struct brcms_phy *pi)
-{
- u16 *loft_comp;
- u16 txcal_coeffs_bphy[4];
- u16 *tbl_ptr;
- int coreNum;
- u16 *txcal_radio_regs = NULL;
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (pi->nphy_iqcal_chanspec_2G == 0)
- return;
-
- tbl_ptr = pi->calibration_cache.txcal_coeffs_2G;
- loft_comp = &pi->calibration_cache.txcal_coeffs_2G[5];
- } else {
- if (pi->nphy_iqcal_chanspec_5G == 0)
- return;
-
- tbl_ptr = pi->calibration_cache.txcal_coeffs_5G;
- loft_comp = &pi->calibration_cache.txcal_coeffs_5G[5];
- }
-
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, 16,
- (void *)tbl_ptr);
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- txcal_coeffs_bphy[0] = tbl_ptr[0];
- txcal_coeffs_bphy[1] = tbl_ptr[1];
- txcal_coeffs_bphy[2] = tbl_ptr[2];
- txcal_coeffs_bphy[3] = tbl_ptr[3];
- } else {
- txcal_coeffs_bphy[0] = 0;
- txcal_coeffs_bphy[1] = 0;
- txcal_coeffs_bphy[2] = 0;
- txcal_coeffs_bphy[3] = 0;
- }
-
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, 16,
- txcal_coeffs_bphy);
-
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, 16, loft_comp);
-
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, 16, loft_comp);
-
- if (NREV_LT(pi->pubpi.phy_rev, 2))
- wlc_phy_tx_iq_war_nphy(pi);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- txcal_radio_regs =
- pi->calibration_cache.txcal_radio_regs_2G;
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_2G[0]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_2G[1]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_2G[2]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_2G[3]);
-
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_2G[4]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_2G[5]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_2G[6]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_2G[7]);
- } else {
- write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL,
- pi->calibration_cache.
- txcal_radio_regs_2G[0]);
- write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL,
- pi->calibration_cache.
- txcal_radio_regs_2G[1]);
- write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM,
- pi->calibration_cache.
- txcal_radio_regs_2G[2]);
- write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM,
- pi->calibration_cache.
- txcal_radio_regs_2G[3]);
- }
-
- wlc_phy_rx_iq_coeffs_nphy(pi, 1,
- &pi->calibration_cache.
- rxcal_coeffs_2G);
- } else {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- txcal_radio_regs =
- pi->calibration_cache.txcal_radio_regs_5G;
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_5G[0]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_5G[1]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_I |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_5G[2]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_FINE_Q |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_5G[3]);
-
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_5G[4]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX0,
- pi->calibration_cache.
- txcal_radio_regs_5G[5]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_I |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_5G[6]);
- write_radio_reg(pi,
- RADIO_2056_TX_LOFT_COARSE_Q |
- RADIO_2056_TX1,
- pi->calibration_cache.
- txcal_radio_regs_5G[7]);
- } else {
- write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL,
- pi->calibration_cache.
- txcal_radio_regs_5G[0]);
- write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL,
- pi->calibration_cache.
- txcal_radio_regs_5G[1]);
- write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM,
- pi->calibration_cache.
- txcal_radio_regs_5G[2]);
- write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM,
- pi->calibration_cache.
- txcal_radio_regs_5G[3]);
- }
-
- wlc_phy_rx_iq_coeffs_nphy(pi, 1,
- &pi->calibration_cache.
- rxcal_coeffs_5G);
+ (const struct nphy_sfo_cfg *)
+ &(t3->PHY_BW1a));
}
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- for (coreNum = 0; coreNum <= 1; coreNum++) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_FINE_I,
- txcal_radio_regs[2 * coreNum]);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_FINE_Q,
- txcal_radio_regs[2 * coreNum + 1]);
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_COARSE_I,
- txcal_radio_regs[2 * coreNum + 4]);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum,
- LOFT_COARSE_Q,
- txcal_radio_regs[2 * coreNum + 5]);
- }
- }
}
void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
@@ -19545,8 +21546,8 @@ u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val)
if (D11REV_IS(pi->sh->corerev, 16)) {
suspended =
- (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ?
- false : true;
+ (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ?
+ false : true;
if (!suspended)
wlapi_suspend_mac_and_wait(pi->sh->physhim);
}
@@ -19563,18 +21564,6 @@ u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val)
return new_ctl;
}
-static void wlc_phy_clip_det_nphy(struct brcms_phy *pi, u8 write, u16 *vals)
-{
-
- if (write == 0) {
- vals[0] = read_phy_reg(pi, 0x2c);
- vals[1] = read_phy_reg(pi, 0x42);
- } else {
- write_phy_reg(pi, 0x2c, vals[0]);
- write_phy_reg(pi, 0x42, vals[1]);
- }
-}
-
void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd)
{
u16 trigger_mask, status_mask;
@@ -19620,577 +21609,6 @@ void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd)
}
static void
-wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys,
- u8 len)
-{
- u32 t1_offset, t2_offset;
- u8 ctr;
- u8 end_event =
- NREV_GE(pi->pubpi.phy_rev,
- 3) ? NPHY_REV3_RFSEQ_CMD_END : NPHY_RFSEQ_CMD_END;
- u8 end_dly = 1;
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- t1_offset = cmd << 4;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t1_offset, 8,
- events);
- t2_offset = t1_offset + 0x080;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t2_offset, 8,
- dlys);
-
- for (ctr = len; ctr < 16; ctr++) {
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
- t1_offset + ctr, 8, &end_event);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
- t2_offset + ctr, 8, &end_dly);
- }
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-}
-
-static u16 wlc_phy_read_lpf_bw_ctl_nphy(struct brcms_phy *pi, u16 offset)
-{
- u16 lpf_bw_ctl_val = 0;
- u16 rx2tx_lpf_rc_lut_offset = 0;
-
- if (offset == 0) {
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- rx2tx_lpf_rc_lut_offset = 0x159;
- } else {
- rx2tx_lpf_rc_lut_offset = 0x154;
- }
- } else {
- rx2tx_lpf_rc_lut_offset = offset;
- }
- wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 1,
- (u32) rx2tx_lpf_rc_lut_offset, 16,
- &lpf_bw_ctl_val);
-
- lpf_bw_ctl_val = lpf_bw_ctl_val & 0x7;
-
- return lpf_bw_ctl_val;
-}
-
-static void
-wlc_phy_rfctrl_override_nphy_rev7(struct brcms_phy *pi, u16 field, u16 value,
- u8 core_mask, u8 off, u8 override_id)
-{
- u8 core_num;
- u16 addr = 0, en_addr = 0, val_addr = 0, en_mask = 0, val_mask = 0;
- u8 val_shift = 0;
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- en_mask = field;
- for (core_num = 0; core_num < 2; core_num++) {
- if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID0) {
-
- switch (field) {
- case (0x1 << 2):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a :
- 0x7d;
- val_mask = (0x1 << 1);
- val_shift = 1;
- break;
- case (0x1 << 3):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a :
- 0x7d;
- val_mask = (0x1 << 2);
- val_shift = 2;
- break;
- case (0x1 << 4):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a :
- 0x7d;
- val_mask = (0x1 << 4);
- val_shift = 4;
- break;
- case (0x1 << 5):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a :
- 0x7d;
- val_mask = (0x1 << 5);
- val_shift = 5;
- break;
- case (0x1 << 6):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a :
- 0x7d;
- val_mask = (0x1 << 6);
- val_shift = 6;
- break;
- case (0x1 << 7):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a :
- 0x7d;
- val_mask = (0x1 << 7);
- val_shift = 7;
- break;
- case (0x1 << 10):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0xf8 :
- 0xfa;
- val_mask = (0x7 << 4);
- val_shift = 4;
- break;
- case (0x1 << 11):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7b :
- 0x7e;
- val_mask = (0xffff << 0);
- val_shift = 0;
- break;
- case (0x1 << 12):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7c :
- 0x7f;
- val_mask = (0xffff << 0);
- val_shift = 0;
- break;
- case (0x3 << 13):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x348 :
- 0x349;
- val_mask = (0xff << 0);
- val_shift = 0;
- break;
- case (0x1 << 13):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x348 :
- 0x349;
- val_mask = (0xf << 0);
- val_shift = 0;
- break;
- default:
- addr = 0xffff;
- break;
- }
- } else if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID1) {
-
- switch (field) {
- case (0x1 << 1):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 1);
- val_shift = 1;
- break;
- case (0x1 << 3):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 3);
- val_shift = 3;
- break;
- case (0x1 << 5):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 5);
- val_shift = 5;
- break;
- case (0x1 << 4):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 4);
- val_shift = 4;
- break;
- case (0x1 << 2):
-
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 2);
- val_shift = 2;
- break;
- case (0x1 << 7):
-
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x7 << 8);
- val_shift = 8;
- break;
- case (0x1 << 11):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 14);
- val_shift = 14;
- break;
- case (0x1 << 10):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 13);
- val_shift = 13;
- break;
- case (0x1 << 9):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 12);
- val_shift = 12;
- break;
- case (0x1 << 8):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 11);
- val_shift = 11;
- break;
- case (0x1 << 6):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 6);
- val_shift = 6;
- break;
- case (0x1 << 0):
- en_addr = (core_num == 0) ? 0x342 :
- 0x343;
- val_addr = (core_num == 0) ? 0x340 :
- 0x341;
- val_mask = (0x1 << 0);
- val_shift = 0;
- break;
- default:
- addr = 0xffff;
- break;
- }
- } else if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID2) {
-
- switch (field) {
- case (0x1 << 3):
- en_addr = (core_num == 0) ? 0x346 :
- 0x347;
- val_addr = (core_num == 0) ? 0x344 :
- 0x345;
- val_mask = (0x1 << 3);
- val_shift = 3;
- break;
- case (0x1 << 1):
- en_addr = (core_num == 0) ? 0x346 :
- 0x347;
- val_addr = (core_num == 0) ? 0x344 :
- 0x345;
- val_mask = (0x1 << 1);
- val_shift = 1;
- break;
- case (0x1 << 0):
- en_addr = (core_num == 0) ? 0x346 :
- 0x347;
- val_addr = (core_num == 0) ? 0x344 :
- 0x345;
- val_mask = (0x1 << 0);
- val_shift = 0;
- break;
- case (0x1 << 2):
- en_addr = (core_num == 0) ? 0x346 :
- 0x347;
- val_addr = (core_num == 0) ? 0x344 :
- 0x345;
- val_mask = (0x1 << 2);
- val_shift = 2;
- break;
- case (0x1 << 4):
- en_addr = (core_num == 0) ? 0x346 :
- 0x347;
- val_addr = (core_num == 0) ? 0x344 :
- 0x345;
- val_mask = (0x1 << 4);
- val_shift = 4;
- break;
- default:
- addr = 0xffff;
- break;
- }
- }
-
- if (off) {
- and_phy_reg(pi, en_addr, ~en_mask);
- and_phy_reg(pi, val_addr, ~val_mask);
- } else {
-
- if ((core_mask == 0)
- || (core_mask & (1 << core_num))) {
- or_phy_reg(pi, en_addr, en_mask);
-
- if (addr != 0xffff) {
- mod_phy_reg(pi, val_addr,
- val_mask,
- (value <<
- val_shift));
- }
- }
- }
- }
- }
-}
-
-static void
-wlc_phy_rfctrl_override_nphy(struct brcms_phy *pi, u16 field, u16 value,
- u8 core_mask, u8 off)
-{
- u8 core_num;
- u16 addr = 0, mask = 0, en_addr = 0, val_addr = 0, en_mask =
- 0, val_mask = 0;
- u8 shift = 0, val_shift = 0;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) {
-
- en_mask = field;
- for (core_num = 0; core_num < 2; core_num++) {
-
- switch (field) {
- case (0x1 << 1):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 0);
- val_shift = 0;
- break;
- case (0x1 << 2):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 1);
- val_shift = 1;
- break;
- case (0x1 << 3):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 2);
- val_shift = 2;
- break;
- case (0x1 << 4):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 4);
- val_shift = 4;
- break;
- case (0x1 << 5):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 5);
- val_shift = 5;
- break;
- case (0x1 << 6):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 6);
- val_shift = 6;
- break;
- case (0x1 << 7):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x1 << 7);
- val_shift = 7;
- break;
- case (0x1 << 8):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x7 << 8);
- val_shift = 8;
- break;
- case (0x1 << 11):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7a : 0x7d;
- val_mask = (0x7 << 13);
- val_shift = 13;
- break;
-
- case (0x1 << 9):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0xf8 : 0xfa;
- val_mask = (0x7 << 0);
- val_shift = 0;
- break;
-
- case (0x1 << 10):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0xf8 : 0xfa;
- val_mask = (0x7 << 4);
- val_shift = 4;
- break;
-
- case (0x1 << 12):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7b : 0x7e;
- val_mask = (0xffff << 0);
- val_shift = 0;
- break;
- case (0x1 << 13):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0x7c : 0x7f;
- val_mask = (0xffff << 0);
- val_shift = 0;
- break;
- case (0x1 << 14):
- en_addr = (core_num == 0) ? 0xe7 : 0xec;
- val_addr = (core_num == 0) ? 0xf9 : 0xfb;
- val_mask = (0x3 << 6);
- val_shift = 6;
- break;
- case (0x1 << 0):
- en_addr = (core_num == 0) ? 0xe5 : 0xe6;
- val_addr = (core_num == 0) ? 0xf9 : 0xfb;
- val_mask = (0x1 << 15);
- val_shift = 15;
- break;
- default:
- addr = 0xffff;
- break;
- }
-
- if (off) {
- and_phy_reg(pi, en_addr, ~en_mask);
- and_phy_reg(pi, val_addr, ~val_mask);
- } else {
-
- if ((core_mask == 0)
- || (core_mask & (1 << core_num))) {
- or_phy_reg(pi, en_addr, en_mask);
-
- if (addr != 0xffff) {
- mod_phy_reg(pi, val_addr,
- val_mask,
- (value <<
- val_shift));
- }
- }
- }
- }
- } else {
-
- if (off) {
- and_phy_reg(pi, 0xec, ~field);
- value = 0x0;
- } else {
- or_phy_reg(pi, 0xec, field);
- }
-
- for (core_num = 0; core_num < 2; core_num++) {
-
- switch (field) {
- case (0x1 << 1):
- case (0x1 << 9):
- case (0x1 << 12):
- case (0x1 << 13):
- case (0x1 << 14):
- addr = 0x78;
-
- core_mask = 0x1;
- break;
- case (0x1 << 2):
- case (0x1 << 3):
- case (0x1 << 4):
- case (0x1 << 5):
- case (0x1 << 6):
- case (0x1 << 7):
- case (0x1 << 8):
- addr = (core_num == 0) ? 0x7a : 0x7d;
- break;
- case (0x1 << 10):
- addr = (core_num == 0) ? 0x7b : 0x7e;
- break;
- case (0x1 << 11):
- addr = (core_num == 0) ? 0x7c : 0x7f;
- break;
- default:
- addr = 0xffff;
- }
-
- switch (field) {
- case (0x1 << 1):
- mask = (0x7 << 3);
- shift = 3;
- break;
- case (0x1 << 9):
- mask = (0x1 << 2);
- shift = 2;
- break;
- case (0x1 << 12):
- mask = (0x1 << 8);
- shift = 8;
- break;
- case (0x1 << 13):
- mask = (0x1 << 9);
- shift = 9;
- break;
- case (0x1 << 14):
- mask = (0xf << 12);
- shift = 12;
- break;
- case (0x1 << 2):
- mask = (0x1 << 0);
- shift = 0;
- break;
- case (0x1 << 3):
- mask = (0x1 << 1);
- shift = 1;
- break;
- case (0x1 << 4):
- mask = (0x1 << 2);
- shift = 2;
- break;
- case (0x1 << 5):
- mask = (0x3 << 4);
- shift = 4;
- break;
- case (0x1 << 6):
- mask = (0x3 << 6);
- shift = 6;
- break;
- case (0x1 << 7):
- mask = (0x1 << 8);
- shift = 8;
- break;
- case (0x1 << 8):
- mask = (0x1 << 9);
- shift = 9;
- break;
- case (0x1 << 10):
- mask = 0x1fff;
- shift = 0x0;
- break;
- case (0x1 << 11):
- mask = 0x1fff;
- shift = 0x0;
- break;
- default:
- mask = 0x0;
- shift = 0x0;
- break;
- }
-
- if ((addr != 0xffff) && (core_mask & (1 << core_num))) {
- mod_phy_reg(pi, addr, mask, (value << shift));
- }
- }
-
- or_phy_reg(pi, 0xec, (0x1 << 0));
- or_phy_reg(pi, 0x78, (0x1 << 0));
- udelay(1);
- and_phy_reg(pi, 0xec, ~(0x1 << 0));
- }
-}
-
-static void
wlc_phy_rfctrl_override_1tomany_nphy(struct brcms_phy *pi, u16 cmd, u16 value,
u8 core_mask, u8 off)
{
@@ -20201,76 +21619,93 @@ wlc_phy_rfctrl_override_1tomany_nphy(struct brcms_phy *pi, u16 cmd, u16 value,
switch (cmd) {
case NPHY_REV7_RfctrlOverride_cmd_rxrf_pu:
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5),
- value, core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 5),
+ value, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 3), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
break;
case NPHY_REV7_RfctrlOverride_cmd_rx_pu:
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2),
- value, core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ value, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 1), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 0), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 1), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 11), 0,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
break;
case NPHY_REV7_RfctrlOverride_cmd_tx_pu:
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2),
- value, core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), value,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 1,
- core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ value, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 1), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 0), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2), value,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 11), 1,
+ core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
break;
case NPHY_REV7_RfctrlOverride_cmd_rxgain:
rfmxgain = value & 0x000ff;
lpfgain = value & 0x0ff00;
lpfgain = lpfgain >> 8;
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11),
- rfmxgain, core_mask,
- off,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x3 << 13),
- lpfgain, core_mask,
- off,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 11),
+ rfmxgain, core_mask,
+ off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x3 << 13),
+ lpfgain, core_mask,
+ off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
break;
case NPHY_REV7_RfctrlOverride_cmd_txgain:
tgain = value & 0x7fff;
lpfgain = value & 0x8000;
lpfgain = lpfgain >> 14;
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
- tgain, core_mask, off,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 13),
- lpfgain, core_mask,
- off,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 12),
+ tgain, core_mask, off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 13),
+ lpfgain, core_mask,
+ off,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
break;
}
}
@@ -20283,137 +21718,164 @@ wlc_phy_scale_offset_rssi_nphy(struct brcms_phy *pi, u16 scale, s8 offset,
u16 valuetostuff;
offset = (offset > NPHY_RSSICAL_MAXREAD) ?
- NPHY_RSSICAL_MAXREAD : offset;
+ NPHY_RSSICAL_MAXREAD : offset;
offset = (offset < (-NPHY_RSSICAL_MAXREAD - 1)) ?
- -NPHY_RSSICAL_MAXREAD - 1 : offset;
+ -NPHY_RSSICAL_MAXREAD - 1 : offset;
valuetostuff = ((scale & 0x3f) << 8) | (offset & 0x3f);
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB))
write_phy_reg(pi, 0x1a6, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB))
write_phy_reg(pi, 0x1ac, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB))
write_phy_reg(pi, 0x1b2, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB))
write_phy_reg(pi, 0x1b8, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1))
write_phy_reg(pi, 0x1a4, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1))
write_phy_reg(pi, 0x1aa, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1))
write_phy_reg(pi, 0x1b0, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1))
write_phy_reg(pi, 0x1b6, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2))
write_phy_reg(pi, 0x1a5, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2))
write_phy_reg(pi, 0x1ab, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2))
write_phy_reg(pi, 0x1b1, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2))
write_phy_reg(pi, 0x1b7, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD))
write_phy_reg(pi, 0x1a7, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD))
write_phy_reg(pi, 0x1ad, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD))
write_phy_reg(pi, 0x1b3, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD))
write_phy_reg(pi, 0x1b9, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ))
write_phy_reg(pi, 0x1a8, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ))
write_phy_reg(pi, 0x1ae, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ)) {
+ (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ))
write_phy_reg(pi, 0x1b4, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ)) {
+ (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ))
write_phy_reg(pi, 0x1ba, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rssi_type == NPHY_RSSI_SEL_TSSI_2G)) {
+ (rssi_type == NPHY_RSSI_SEL_TSSI_2G))
write_phy_reg(pi, 0x1a9, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rssi_type == NPHY_RSSI_SEL_TSSI_2G)) {
+ (rssi_type == NPHY_RSSI_SEL_TSSI_2G))
write_phy_reg(pi, 0x1b5, valuetostuff);
- }
if (((coresel == RADIO_MIMO_CORESEL_CORE1) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rssi_type == NPHY_RSSI_SEL_TSSI_5G)) {
+ (rssi_type == NPHY_RSSI_SEL_TSSI_5G))
write_phy_reg(pi, 0x1af, valuetostuff);
- }
+
if (((coresel == RADIO_MIMO_CORESEL_CORE2) ||
(coresel == RADIO_MIMO_CORESEL_ALLRX)) &&
- (rssi_type == NPHY_RSSI_SEL_TSSI_5G)) {
+ (rssi_type == NPHY_RSSI_SEL_TSSI_5G))
write_phy_reg(pi, 0x1bb, valuetostuff);
+}
+
+static void brcms_phy_wr_tx_mux(struct brcms_phy *pi, u8 core)
+{
+ if (PHY_IPA(pi)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ write_radio_reg(pi,
+ ((core == PHY_CORE_0) ?
+ RADIO_2057_TX0_TX_SSI_MUX :
+ RADIO_2057_TX1_TX_SSI_MUX),
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0xc : 0xe));
+ else
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ ((core == PHY_CORE_0) ?
+ RADIO_2056_TX0 : RADIO_2056_TX1),
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0xc : 0xe));
+ } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ write_radio_reg(pi,
+ ((core == PHY_CORE_0) ?
+ RADIO_2057_TX0_TX_SSI_MUX :
+ RADIO_2057_TX1_TX_SSI_MUX),
+ 0x11);
+
+ if (pi->pubpi.radioid == BCM2057_ID)
+ write_radio_reg(pi,
+ RADIO_2057_IQTEST_SEL_PU, 0x1);
+
+ } else {
+ write_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ ((core == PHY_CORE_0) ?
+ RADIO_2056_TX0 : RADIO_2056_TX1),
+ 0x11);
+ }
}
}
@@ -20440,7 +21902,7 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
mod_phy_reg(pi, 0xe6, (0x1 << 5), 0);
mask = (0x1 << 2) |
- (0x1 << 3) | (0x1 << 4) | (0x1 << 5);
+ (0x1 << 3) | (0x1 << 4) | (0x1 << 5);
mod_phy_reg(pi, 0xf9, mask, 0);
mod_phy_reg(pi, 0xfb, mask, 0);
@@ -20459,23 +21921,22 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
if (rssi_type == NPHY_RSSI_SEL_W1 ||
rssi_type == NPHY_RSSI_SEL_W2 ||
rssi_type == NPHY_RSSI_SEL_NB) {
-
mod_phy_reg(pi,
(core ==
PHY_CORE_0) ? 0xa6 : 0xa7,
(0x3 << 8), 0);
mask = (0x1 << 2) |
- (0x1 << 3) |
- (0x1 << 4) | (0x1 << 5);
+ (0x1 << 3) |
+ (0x1 << 4) | (0x1 << 5);
mod_phy_reg(pi,
(core ==
PHY_CORE_0) ? 0xf9 : 0xfb,
mask, 0);
if (rssi_type == NPHY_RSSI_SEL_W1) {
- if (CHSPEC_IS5G
- (pi->radio_chanspec)) {
+ if (CHSPEC_IS5G(
+ pi->radio_chanspec)) {
mask = (0x1 << 2);
val = 1 << 2;
} else {
@@ -20501,7 +21962,6 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
0xe5 : 0xe6, mask, val);
} else {
if (rssi_type == NPHY_RSSI_SEL_TBD) {
-
mask = (0x3 << 8);
val = 1 << 8;
mod_phy_reg(pi,
@@ -20516,7 +21976,6 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
: 0xa7, mask, val);
} else if (rssi_type ==
NPHY_RSSI_SEL_IQ) {
-
mask = (0x3 << 8);
val = 2 << 8;
mod_phy_reg(pi,
@@ -20530,7 +21989,6 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
PHY_CORE_0) ? 0xa6
: 0xa7, mask, val);
} else {
-
mask = (0x3 << 8);
val = 3 << 8;
mod_phy_reg(pi,
@@ -20543,86 +22001,13 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
(core ==
PHY_CORE_0) ? 0xa6
: 0xa7, mask, val);
-
- if (PHY_IPA(pi)) {
- if (NREV_GE
- (pi->pubpi.phy_rev,
- 7)) {
-
- write_radio_reg
- (pi,
- ((core ==
- PHY_CORE_0)
- ?
- RADIO_2057_TX0_TX_SSI_MUX
- :
- RADIO_2057_TX1_TX_SSI_MUX),
- (CHSPEC_IS5G
- (pi->
- radio_chanspec)
- ? 0xc :
- 0xe));
- } else {
- write_radio_reg
- (pi,
- RADIO_2056_TX_TX_SSI_MUX
- |
- ((core ==
- PHY_CORE_0)
- ?
- RADIO_2056_TX0
- :
- RADIO_2056_TX1),
- (CHSPEC_IS5G
- (pi->
- radio_chanspec)
- ? 0xc :
- 0xe));
- }
- } else {
-
- if (NREV_GE
- (pi->pubpi.phy_rev,
- 7)) {
- write_radio_reg
- (pi,
- ((core ==
- PHY_CORE_0)
- ?
- RADIO_2057_TX0_TX_SSI_MUX
- :
- RADIO_2057_TX1_TX_SSI_MUX),
- 0x11);
-
- if (pi->pubpi.
- radioid ==
- BCM2057_ID)
- write_radio_reg
- (pi,
- RADIO_2057_IQTEST_SEL_PU,
- 0x1);
-
- } else {
- write_radio_reg
- (pi,
- RADIO_2056_TX_TX_SSI_MUX
- |
- ((core ==
- PHY_CORE_0)
- ?
- RADIO_2056_TX0
- :
- RADIO_2056_TX1),
- 0x11);
- }
- }
-
+ brcms_phy_wr_tx_mux(pi, core);
afectrlovr_rssi_val = 1 << 9;
mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x8f
- : 0xa5, (0x1 << 9),
- afectrlovr_rssi_val);
+ (core ==
+ PHY_CORE_0) ? 0x8f
+ : 0xa5, (0x1 << 9),
+ afectrlovr_rssi_val);
}
}
}
@@ -20631,19 +22016,15 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
if ((rssi_type == NPHY_RSSI_SEL_W1) ||
(rssi_type == NPHY_RSSI_SEL_W2) ||
- (rssi_type == NPHY_RSSI_SEL_NB)) {
-
+ (rssi_type == NPHY_RSSI_SEL_NB))
val = 0x0;
- } else if (rssi_type == NPHY_RSSI_SEL_TBD) {
-
+ else if (rssi_type == NPHY_RSSI_SEL_TBD)
val = 0x1;
- } else if (rssi_type == NPHY_RSSI_SEL_IQ) {
-
+ else if (rssi_type == NPHY_RSSI_SEL_IQ)
val = 0x2;
- } else {
-
+ else
val = 0x3;
- }
+
mask = ((0x3 << 12) | (0x3 << 14));
val = (val << 12) | (val << 14);
mod_phy_reg(pi, 0xa6, mask, val);
@@ -20652,15 +22033,13 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
if ((rssi_type == NPHY_RSSI_SEL_W1) ||
(rssi_type == NPHY_RSSI_SEL_W2) ||
(rssi_type == NPHY_RSSI_SEL_NB)) {
- if (rssi_type == NPHY_RSSI_SEL_W1) {
+ if (rssi_type == NPHY_RSSI_SEL_W1)
val = 0x1;
- }
- if (rssi_type == NPHY_RSSI_SEL_W2) {
+ if (rssi_type == NPHY_RSSI_SEL_W2)
val = 0x2;
- }
- if (rssi_type == NPHY_RSSI_SEL_NB) {
+ if (rssi_type == NPHY_RSSI_SEL_NB)
val = 0x3;
- }
+
mask = (0x3 << 4);
val = (val << 4);
mod_phy_reg(pi, 0x7a, mask, val);
@@ -20698,16 +22077,16 @@ void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type)
(rssi_type == NPHY_RSSI_SEL_NB)) {
rfctrlcmd_mask = ((0x1 << 8) | (0x7 << 3));
rfctrlcmd_val = (rfctrlcmd_rxen_val << 8) |
- (rfctrlcmd_coresel_val << 3);
+ (rfctrlcmd_coresel_val << 3);
rfctrlovr_mask = ((0x1 << 5) |
(0x1 << 12) |
(0x1 << 1) | (0x1 << 0));
rfctrlovr_val = (rfctrlovr_rssi_val <<
5) |
- (rfctrlovr_rxen_val << 12) |
- (rfctrlovr_coresel_val << 1) |
- (rfctrlovr_trigger_val << 0);
+ (rfctrlovr_rxen_val << 12) |
+ (rfctrlovr_coresel_val << 1) |
+ (rfctrlovr_trigger_val << 0);
mod_phy_reg(pi, 0x78, rfctrlcmd_mask, rfctrlcmd_val);
mod_phy_reg(pi, 0xec, rfctrlovr_mask, rfctrlovr_val);
@@ -20762,13 +22141,11 @@ wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, s32 *rssi_buf,
wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type);
gpiosel_orig = read_phy_reg(pi, 0xca);
- if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
write_phy_reg(pi, 0xca, 5);
- }
- for (ctr = 0; ctr < 4; ctr++) {
+ for (ctr = 0; ctr < 4; ctr++)
rssi_buf[ctr] = 0;
- }
for (samp = 0; samp < nsamps; samp++) {
if (NREV_LT(pi->pubpi.phy_rev, 2)) {
@@ -20785,9 +22162,8 @@ wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, s32 *rssi_buf,
tmp_buf[ctr++] = ((s8) ((rssi1 & 0x3f) << 2)) >> 2;
tmp_buf[ctr++] = ((s8) (((rssi1 >> 8) & 0x3f) << 2)) >> 2;
- for (ctr = 0; ctr < 4; ctr++) {
+ for (ctr = 0; ctr < 4; ctr++)
rssi_buf[ctr] += tmp_buf[ctr];
- }
}
@@ -20796,9 +22172,8 @@ wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, s32 *rssi_buf,
rssi_out_val |= (rssi_buf[1] & 0xff) << 16;
rssi_out_val |= (rssi_buf[0] & 0xff) << 24;
- if (NREV_LT(pi->pubpi.phy_rev, 2)) {
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
write_phy_reg(pi, 0xca, gpiosel_orig);
- }
write_phy_reg(pi, 0xa6, afectrlCore1_save);
write_phy_reg(pi, 0xa7, afectrlCore2_save);
@@ -20848,7 +22223,7 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi)
u16 tempsense_Rcal;
syn_tempprocsense_save =
- read_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG);
+ read_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG);
afectrlCore1_save = read_phy_reg(pi, 0xa6);
afectrlCore2_save = read_phy_reg(pi, 0xa7);
@@ -20982,7 +22357,7 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi)
} else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
syn_tempprocsense_save =
- read_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE);
+ read_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE);
afectrlCore1_save = read_phy_reg(pi, 0xa6);
afectrlCore2_save = read_phy_reg(pi, 0xa7);
@@ -20997,14 +22372,13 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi)
write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x05);
wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x01);
- } else {
+ else
write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01);
- }
radio_temp[0] =
- (126 * (radio_temp[1] + radio_temp2[1]) + 3987) / 64;
+ (126 * (radio_temp[1] + radio_temp2[1]) + 3987) / 64;
write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE,
syn_tempprocsense_save);
@@ -21019,17 +22393,17 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi)
} else {
pwrdet_rxtx_core1_save =
- read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1);
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1);
pwrdet_rxtx_core2_save =
- read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2);
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2);
core1_txrf_iqcal1_save =
- read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1);
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1);
core1_txrf_iqcal2_save =
- read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2);
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2);
core2_txrf_iqcal1_save =
- read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1);
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1);
core2_txrf_iqcal2_save =
- read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2);
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2);
pd_pll_ts_save = read_radio_reg(pi, RADIO_2055_PD_PLL_TS);
afectrlCore1_save = read_phy_reg(pi, 0xa6);
@@ -21060,11 +22434,12 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi)
radio_temp[3] = (radio_temp[3] + radio_temp2[3]);
radio_temp[0] =
- (radio_temp[0] + radio_temp[1] + radio_temp[2] +
- radio_temp[3]);
+ (radio_temp[0] + radio_temp[1] + radio_temp[2] +
+ radio_temp[3]);
radio_temp[0] =
- (radio_temp[0] + (8 * 32)) * (950 - 350) / 63 + (350 * 8);
+ (radio_temp[0] +
+ (8 * 32)) * (950 - 350) / 63 + (350 * 8);
radio_temp[0] = (radio_temp[0] - (8 * 420)) / 38;
@@ -21126,521 +22501,24 @@ wlc_phy_set_rssi_2055_vcm(struct brcms_phy *pi, u8 rssi_type, u8 *vcm_buf)
RADIO_2055_NBRSSI_VCM_Q_SHIFT);
}
} else {
-
- if (core == PHY_CORE_0) {
+ if (core == PHY_CORE_0)
mod_radio_reg(pi,
RADIO_2055_CORE1_RXBB_RSSI_CTRL5,
RADIO_2055_WBRSSI_VCM_IQ_MASK,
vcm_buf[2 *
core] <<
RADIO_2055_WBRSSI_VCM_IQ_SHIFT);
- } else {
+ else
mod_radio_reg(pi,
RADIO_2055_CORE2_RXBB_RSSI_CTRL5,
RADIO_2055_WBRSSI_VCM_IQ_MASK,
vcm_buf[2 *
core] <<
RADIO_2055_WBRSSI_VCM_IQ_SHIFT);
- }
}
}
}
-void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi)
-{
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
- wlc_phy_rssi_cal_nphy_rev3(pi);
- } else {
- wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_NB);
- wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W1);
- wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W2);
- }
-}
-
-static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type)
-{
- s32 target_code;
- u16 classif_state;
- u16 clip_state[2];
- u16 rssi_ctrl_state[2], pd_state[2];
- u16 rfctrlintc_state[2], rfpdcorerxtx_state[2];
- u16 rfctrlintc_override_val;
- u16 clip_off[] = { 0xffff, 0xffff };
- u16 rf_pd_val, pd_mask, rssi_ctrl_mask;
- u8 vcm, min_vcm, vcm_tmp[4];
- u8 vcm_final[4] = { 0, 0, 0, 0 };
- u8 result_idx, ctr;
- s32 poll_results[4][4] = {
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0},
- {0, 0, 0, 0}
- };
- s32 poll_miniq[4][2] = {
- {0, 0},
- {0, 0},
- {0, 0},
- {0, 0}
- };
- s32 min_d, curr_d;
- s32 fine_digital_offset[4];
- s32 poll_results_min[4] = { 0, 0, 0, 0 };
- s32 min_poll;
-
- switch (rssi_type) {
- case NPHY_RSSI_SEL_NB:
- target_code = NPHY_RSSICAL_NB_TARGET;
- break;
- case NPHY_RSSI_SEL_W1:
- target_code = NPHY_RSSICAL_W1_TARGET;
- break;
- case NPHY_RSSI_SEL_W2:
- target_code = NPHY_RSSICAL_W2_TARGET;
- break;
- default:
- return;
- break;
- }
-
- classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
- wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
- wlc_phy_clip_det_nphy(pi, 0, clip_state);
- wlc_phy_clip_det_nphy(pi, 1, clip_off);
-
- rf_pd_val = (rssi_type == NPHY_RSSI_SEL_NB) ? 0x6 : 0x4;
- rfctrlintc_override_val =
- CHSPEC_IS5G(pi->radio_chanspec) ? 0x140 : 0x110;
-
- rfctrlintc_state[0] = read_phy_reg(pi, 0x91);
- rfpdcorerxtx_state[0] = read_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX);
- write_phy_reg(pi, 0x91, rfctrlintc_override_val);
- write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rf_pd_val);
-
- rfctrlintc_state[1] = read_phy_reg(pi, 0x92);
- rfpdcorerxtx_state[1] = read_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX);
- write_phy_reg(pi, 0x92, rfctrlintc_override_val);
- write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rf_pd_val);
-
- pd_mask = RADIO_2055_NBRSSI_PD | RADIO_2055_WBRSSI_G1_PD |
- RADIO_2055_WBRSSI_G2_PD;
- pd_state[0] =
- read_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC) & pd_mask;
- pd_state[1] =
- read_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC) & pd_mask;
- mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, 0);
- mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, 0);
- rssi_ctrl_mask = RADIO_2055_NBRSSI_SEL | RADIO_2055_WBRSSI_G1_SEL |
- RADIO_2055_WBRSSI_G2_SEL;
- rssi_ctrl_state[0] =
- read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE1) & rssi_ctrl_mask;
- rssi_ctrl_state[1] =
- read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE2) & rssi_ctrl_mask;
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type);
-
- wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX,
- NPHY_RAIL_I, rssi_type);
- wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX,
- NPHY_RAIL_Q, rssi_type);
-
- for (vcm = 0; vcm < 4; vcm++) {
-
- vcm_tmp[0] = vcm_tmp[1] = vcm_tmp[2] = vcm_tmp[3] = vcm;
- if (rssi_type != NPHY_RSSI_SEL_W2) {
- wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_tmp);
- }
-
- wlc_phy_poll_rssi_nphy(pi, rssi_type, &poll_results[vcm][0],
- NPHY_RSSICAL_NPOLL);
-
- if ((rssi_type == NPHY_RSSI_SEL_W1)
- || (rssi_type == NPHY_RSSI_SEL_W2)) {
- for (ctr = 0; ctr < 2; ctr++) {
- poll_miniq[vcm][ctr] =
- min(poll_results[vcm][ctr * 2 + 0],
- poll_results[vcm][ctr * 2 + 1]);
- }
- }
- }
-
- for (result_idx = 0; result_idx < 4; result_idx++) {
- min_d = NPHY_RSSICAL_MAXD;
- min_vcm = 0;
- min_poll = NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL + 1;
- for (vcm = 0; vcm < 4; vcm++) {
- curr_d = ABS(((rssi_type == NPHY_RSSI_SEL_NB) ?
- poll_results[vcm][result_idx] :
- poll_miniq[vcm][result_idx / 2]) -
- (target_code * NPHY_RSSICAL_NPOLL));
- if (curr_d < min_d) {
- min_d = curr_d;
- min_vcm = vcm;
- }
- if (poll_results[vcm][result_idx] < min_poll) {
- min_poll = poll_results[vcm][result_idx];
- }
- }
- vcm_final[result_idx] = min_vcm;
- poll_results_min[result_idx] = min_poll;
- }
-
- if (rssi_type != NPHY_RSSI_SEL_W2) {
- wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_final);
- }
-
- for (result_idx = 0; result_idx < 4; result_idx++) {
- fine_digital_offset[result_idx] =
- (target_code * NPHY_RSSICAL_NPOLL) -
- poll_results[vcm_final[result_idx]][result_idx];
- if (fine_digital_offset[result_idx] < 0) {
- fine_digital_offset[result_idx] =
- ABS(fine_digital_offset[result_idx]);
- fine_digital_offset[result_idx] +=
- (NPHY_RSSICAL_NPOLL / 2);
- fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL;
- fine_digital_offset[result_idx] =
- -fine_digital_offset[result_idx];
- } else {
- fine_digital_offset[result_idx] +=
- (NPHY_RSSICAL_NPOLL / 2);
- fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL;
- }
-
- if (poll_results_min[result_idx] ==
- NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL) {
- fine_digital_offset[result_idx] =
- (target_code - NPHY_RSSICAL_MAXREAD - 1);
- }
-
- wlc_phy_scale_offset_rssi_nphy(pi, 0x0,
- (s8)
- fine_digital_offset[result_idx],
- (result_idx / 2 ==
- 0) ? RADIO_MIMO_CORESEL_CORE1 :
- RADIO_MIMO_CORESEL_CORE2,
- (result_idx % 2 ==
- 0) ? NPHY_RAIL_I : NPHY_RAIL_Q,
- rssi_type);
- }
-
- mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, pd_state[0]);
- mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, pd_state[1]);
- if (rssi_ctrl_state[0] == RADIO_2055_NBRSSI_SEL) {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
- NPHY_RSSI_SEL_NB);
- } else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G1_SEL) {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
- NPHY_RSSI_SEL_W1);
- } else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G2_SEL) {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
- NPHY_RSSI_SEL_W2);
- } else {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
- NPHY_RSSI_SEL_W2);
- }
- if (rssi_ctrl_state[1] == RADIO_2055_NBRSSI_SEL) {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
- NPHY_RSSI_SEL_NB);
- } else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G1_SEL) {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
- NPHY_RSSI_SEL_W1);
- } else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G2_SEL) {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
- NPHY_RSSI_SEL_W2);
- } else {
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
- NPHY_RSSI_SEL_W2);
- }
-
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, rssi_type);
-
- write_phy_reg(pi, 0x91, rfctrlintc_state[0]);
- write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rfpdcorerxtx_state[0]);
- write_phy_reg(pi, 0x92, rfctrlintc_state[1]);
- write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rfpdcorerxtx_state[1]);
-
- wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
- wlc_phy_clip_det_nphy(pi, 1, clip_state);
-
- wlc_phy_resetcca_nphy(pi);
-}
-
-int
-wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct brcms_d11rxhdr *wlc_rxh)
-{
- struct d11rxhdr *rxh = &wlc_rxh->rxhdr;
- s16 rxpwr, rxpwr0, rxpwr1;
- s16 phyRx0_l, phyRx2_l;
-
- rxpwr = 0;
- rxpwr0 = le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_nphy_PWR0_MASK;
- rxpwr1 = (le16_to_cpu(rxh->PhyRxStatus_1) & PRXS1_nphy_PWR1_MASK) >> 8;
-
- if (rxpwr0 > 127)
- rxpwr0 -= 256;
- if (rxpwr1 > 127)
- rxpwr1 -= 256;
-
- phyRx0_l = le16_to_cpu(rxh->PhyRxStatus_0) & 0x00ff;
- phyRx2_l = le16_to_cpu(rxh->PhyRxStatus_2) & 0x00ff;
- if (phyRx2_l > 127)
- phyRx2_l -= 256;
-
- if (((rxpwr0 == 16) || (rxpwr0 == 32))) {
- rxpwr0 = rxpwr1;
- rxpwr1 = phyRx2_l;
- }
-
- wlc_rxh->rxpwr[0] = (s8) rxpwr0;
- wlc_rxh->rxpwr[1] = (s8) rxpwr1;
- wlc_rxh->do_rssi_ma = 0;
-
- if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MAX)
- rxpwr = (rxpwr0 > rxpwr1) ? rxpwr0 : rxpwr1;
- else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MIN)
- rxpwr = (rxpwr0 < rxpwr1) ? rxpwr0 : rxpwr1;
- else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_AVG)
- rxpwr = (rxpwr0 + rxpwr1) >> 1;
-
- return rxpwr;
-}
-
-static void
-wlc_phy_rfctrlintc_override_nphy(struct brcms_phy *pi, u8 field, u16 value,
- u8 core_code)
-{
- u16 mask;
- u16 val;
- u8 core;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- if (core_code == RADIO_MIMO_CORESEL_CORE1
- && core == PHY_CORE_1)
- continue;
- else if (core_code == RADIO_MIMO_CORESEL_CORE2
- && core == PHY_CORE_0)
- continue;
-
- if (NREV_LT(pi->pubpi.phy_rev, 7)) {
-
- mask = (0x1 << 10);
- val = 1 << 10;
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 :
- 0x92, mask, val);
- }
-
- if (field == NPHY_RfctrlIntc_override_OFF) {
-
- write_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 :
- 0x92, 0);
-
- wlc_phy_force_rfseq_nphy(pi,
- NPHY_RFSEQ_RESET2RX);
- } else if (field == NPHY_RfctrlIntc_override_TRSW) {
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- mask = (0x1 << 6) | (0x1 << 7);
-
- val = value << 6;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
-
- or_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- (0x1 << 10));
-
- and_phy_reg(pi, 0x2ff, (u16)
- ~(0x3 << 14));
- or_phy_reg(pi, 0x2ff, (0x1 << 13));
- or_phy_reg(pi, 0x2ff, (0x1 << 0));
- } else {
-
- mask = (0x1 << 6) |
- (0x1 << 7) |
- (0x1 << 8) | (0x1 << 9);
- val = value << 6;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
-
- mask = (0x1 << 0);
- val = 1 << 0;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0xe7 : 0xec,
- mask, val);
-
- mask = (core == PHY_CORE_0) ? (0x1 << 0)
- : (0x1 << 1);
- val = 1 << ((core == PHY_CORE_0) ?
- 0 : 1);
- mod_phy_reg(pi, 0x78, mask, val);
-
- SPINWAIT(((read_phy_reg(pi, 0x78) & val)
- != 0), 10000);
- if (WARN(read_phy_reg(pi, 0x78) & val,
- "HW error: override failed"))
- return;
-
- mask = (0x1 << 0);
- val = 0 << 0;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0xe7 : 0xec,
- mask, val);
- }
- } else if (field == NPHY_RfctrlIntc_override_PA) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- mask = (0x1 << 4) | (0x1 << 5);
-
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- val = value << 5;
- } else {
- val = value << 4;
- }
-
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
-
- or_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- (0x1 << 12));
- } else {
-
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- mask = (0x1 << 5);
- val = value << 5;
- } else {
- mask = (0x1 << 4);
- val = value << 4;
- }
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
- }
- } else if (field == NPHY_RfctrlIntc_override_EXT_LNA_PU) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
-
- mask = (0x1 << 0);
- val = value << 0;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, val);
-
- mask = (0x1 << 2);
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, 0);
- } else {
-
- mask = (0x1 << 2);
- val = value << 2;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, val);
-
- mask = (0x1 << 0);
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, 0);
- }
-
- mask = (0x1 << 11);
- val = 1 << 11;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
- } else {
-
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- mask = (0x1 << 0);
- val = value << 0;
- } else {
- mask = (0x1 << 2);
- val = value << 2;
- }
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
- }
- } else if (field ==
- NPHY_RfctrlIntc_override_EXT_LNA_GAIN) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
-
- mask = (0x1 << 1);
- val = value << 1;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, val);
-
- mask = (0x1 << 3);
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, 0);
- } else {
-
- mask = (0x1 << 3);
- val = value << 3;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, val);
-
- mask = (0x1 << 1);
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91
- : 0x92, mask, 0);
- }
-
- mask = (0x1 << 11);
- val = 1 << 11;
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
- } else {
-
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- mask = (0x1 << 1);
- val = value << 1;
- } else {
- mask = (0x1 << 3);
- val = value << 3;
- }
- mod_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0x91 : 0x92,
- mask, val);
- }
- }
- }
- } else {
- return;
- }
-}
-
static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
{
u16 classif_state;
@@ -21683,10 +22561,14 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
u16 NPHY_REV7_RfctrlMiscReg3_save, NPHY_REV7_RfctrlMiscReg4_save;
u16 NPHY_REV7_RfctrlMiscReg5_save, NPHY_REV7_RfctrlMiscReg6_save;
- NPHY_REV7_RfctrlOverride3_save = NPHY_REV7_RfctrlOverride4_save =
- NPHY_REV7_RfctrlOverride5_save = NPHY_REV7_RfctrlOverride6_save =
- NPHY_REV7_RfctrlMiscReg3_save = NPHY_REV7_RfctrlMiscReg4_save =
- NPHY_REV7_RfctrlMiscReg5_save = NPHY_REV7_RfctrlMiscReg6_save = 0;
+ NPHY_REV7_RfctrlOverride3_save =
+ NPHY_REV7_RfctrlOverride4_save =
+ NPHY_REV7_RfctrlOverride5_save =
+ NPHY_REV7_RfctrlOverride6_save =
+ NPHY_REV7_RfctrlMiscReg3_save =
+ NPHY_REV7_RfctrlMiscReg4_save =
+ NPHY_REV7_RfctrlMiscReg5_save =
+ NPHY_REV7_RfctrlMiscReg6_save = 0;
classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
@@ -21726,21 +22608,21 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_TRSW, 1,
RADIO_MIMO_CORESEL_ALLRXTX);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_rxrf_pu,
- 0, 0, 0);
- } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxrf_pu,
+ 0, 0, 0);
+ else
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0, 0);
- }
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_rx_pu,
- 1, 0, 0);
- } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rx_pu,
+ 1, 0, 0);
+ else
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0, 0);
- }
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7),
@@ -21755,12 +22637,14 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
if (CHSPEC_IS5G(pi->radio_chanspec)) {
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5),
- 0, 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 1, 0,
- 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 5),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4), 1, 0,
+ 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
} else {
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 0, 0, 0);
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 1, 0, 0);
@@ -21768,12 +22652,14 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
} else {
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4),
- 0, 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 1, 0,
- 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 4),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 5), 1, 0,
+ 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
} else {
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 0, 0, 0);
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 1, 0, 0);
@@ -21781,7 +22667,7 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
}
rxcore_state = wlc_phy_rxcore_getstate_nphy(
- (struct brcms_phy_pub *) pi);
+ (struct brcms_phy_pub *) pi);
vcm_level_max = 8;
@@ -21804,21 +22690,18 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
NPHY_RAIL_Q, NPHY_RSSI_SEL_NB);
for (vcm = 0; vcm < vcm_level_max; vcm++) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
mod_radio_reg(pi, (core == PHY_CORE_0) ?
RADIO_2057_NB_MASTER_CORE0 :
RADIO_2057_NB_MASTER_CORE1,
RADIO_2057_VCM_MASK, vcm);
- } else {
-
+ else
mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC |
((core ==
PHY_CORE_0) ? RADIO_2056_RX0 :
RADIO_2056_RX1),
RADIO_2056_VCM_MASK,
vcm << RADIO_2056_RSSI_VCM_SHIFT);
- }
wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_NB,
&poll_results[vcm][0],
@@ -21826,92 +22709,90 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
}
for (result_idx = 0; result_idx < 4; result_idx++) {
- if ((core == result_idx / 2) && (result_idx % 2 == 0)) {
+ if ((core == result_idx / 2) &&
+ (result_idx % 2 == 0)) {
min_d = NPHY_RSSICAL_MAXD;
min_vcm = 0;
min_poll =
- NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL +
- 1;
+ NPHY_RSSICAL_MAXREAD *
+ NPHY_RSSICAL_NPOLL + 1;
for (vcm = 0; vcm < vcm_level_max; vcm++) {
- curr_d = poll_results[vcm][result_idx] *
- poll_results[vcm][result_idx] +
- poll_results[vcm][result_idx + 1] *
- poll_results[vcm][result_idx + 1];
+ curr_d =
+ poll_results[vcm][result_idx] *
+ poll_results[vcm][result_idx] +
+ poll_results[vcm][result_idx +
+ 1] *
+ poll_results[vcm][result_idx +
+ 1];
if (curr_d < min_d) {
min_d = curr_d;
min_vcm = vcm;
}
if (poll_results[vcm][result_idx] <
- min_poll) {
+ min_poll)
min_poll =
- poll_results[vcm]
- [result_idx];
- }
+ poll_results[vcm]
+ [result_idx];
}
vcm_final = min_vcm;
poll_results_min[result_idx] = min_poll;
}
}
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
mod_radio_reg(pi, (core == PHY_CORE_0) ?
RADIO_2057_NB_MASTER_CORE0 :
RADIO_2057_NB_MASTER_CORE1,
RADIO_2057_VCM_MASK, vcm_final);
- } else {
+ else
mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC |
((core ==
PHY_CORE_0) ? RADIO_2056_RX0 :
RADIO_2056_RX1), RADIO_2056_VCM_MASK,
vcm_final << RADIO_2056_RSSI_VCM_SHIFT);
- }
for (result_idx = 0; result_idx < 4; result_idx++) {
if (core == result_idx / 2) {
fine_digital_offset[result_idx] =
- (NPHY_RSSICAL_NB_TARGET *
- NPHY_RSSICAL_NPOLL) -
- poll_results[vcm_final][result_idx];
+ (NPHY_RSSICAL_NB_TARGET *
+ NPHY_RSSICAL_NPOLL) -
+ poll_results[vcm_final][result_idx];
if (fine_digital_offset[result_idx] < 0) {
fine_digital_offset[result_idx] =
- ABS(fine_digital_offset
- [result_idx]);
+ abs(fine_digital_offset
+ [result_idx]);
fine_digital_offset[result_idx] +=
- (NPHY_RSSICAL_NPOLL / 2);
+ (NPHY_RSSICAL_NPOLL / 2);
fine_digital_offset[result_idx] /=
- NPHY_RSSICAL_NPOLL;
+ NPHY_RSSICAL_NPOLL;
fine_digital_offset[result_idx] =
- -fine_digital_offset[result_idx];
+ -fine_digital_offset[
+ result_idx];
} else {
fine_digital_offset[result_idx] +=
- (NPHY_RSSICAL_NPOLL / 2);
+ (NPHY_RSSICAL_NPOLL / 2);
fine_digital_offset[result_idx] /=
- NPHY_RSSICAL_NPOLL;
+ NPHY_RSSICAL_NPOLL;
}
if (poll_results_min[result_idx] ==
- NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL) {
+ NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL)
fine_digital_offset[result_idx] =
- (NPHY_RSSICAL_NB_TARGET -
- NPHY_RSSICAL_MAXREAD - 1);
- }
-
- wlc_phy_scale_offset_rssi_nphy(pi, 0x0,
- (s8)
- fine_digital_offset
- [result_idx],
- (result_idx /
- 2 ==
- 0) ?
- RADIO_MIMO_CORESEL_CORE1
- :
- RADIO_MIMO_CORESEL_CORE2,
- (result_idx %
- 2 ==
- 0) ? NPHY_RAIL_I
- : NPHY_RAIL_Q,
- NPHY_RSSI_SEL_NB);
+ (NPHY_RSSICAL_NB_TARGET -
+ NPHY_RSSICAL_MAXREAD - 1);
+
+ wlc_phy_scale_offset_rssi_nphy(
+ pi, 0x0,
+ (s8)
+ fine_digital_offset
+ [result_idx],
+ (result_idx / 2 == 0) ?
+ RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ (result_idx % 2 == 0) ?
+ NPHY_RAIL_I : NPHY_RAIL_Q,
+ NPHY_RSSI_SEL_NB);
}
}
@@ -21952,46 +22833,44 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
for (result_idx = 0; result_idx < 4; result_idx++) {
if (core == result_idx / 2) {
fine_digital_offset[result_idx] =
- (target_code * NPHY_RSSICAL_NPOLL) -
- poll_result_core[result_idx];
- if (fine_digital_offset[result_idx] < 0) {
+ (target_code *
+ NPHY_RSSICAL_NPOLL) -
+ poll_result_core[result_idx];
+ if (fine_digital_offset[result_idx] <
+ 0) {
fine_digital_offset[result_idx]
- =
- ABS(fine_digital_offset
- [result_idx]);
+ = abs(
+ fine_digital_offset
+ [result_idx]);
fine_digital_offset[result_idx]
- += (NPHY_RSSICAL_NPOLL / 2);
+ += (NPHY_RSSICAL_NPOLL
+ / 2);
fine_digital_offset[result_idx]
- /= NPHY_RSSICAL_NPOLL;
+ /= NPHY_RSSICAL_NPOLL;
fine_digital_offset[result_idx]
- =
- -fine_digital_offset
- [result_idx];
+ = -fine_digital_offset
+ [result_idx];
} else {
fine_digital_offset[result_idx]
- += (NPHY_RSSICAL_NPOLL / 2);
+ += (NPHY_RSSICAL_NPOLL
+ / 2);
fine_digital_offset[result_idx]
- /= NPHY_RSSICAL_NPOLL;
+ /= NPHY_RSSICAL_NPOLL;
}
- wlc_phy_scale_offset_rssi_nphy(pi, 0x0,
- (s8)
- fine_digital_offset
- [core *
- 2],
- (core ==
- PHY_CORE_0)
- ?
- RADIO_MIMO_CORESEL_CORE1
- :
- RADIO_MIMO_CORESEL_CORE2,
- (result_idx
- % 2 ==
- 0) ?
- NPHY_RAIL_I
- :
- NPHY_RAIL_Q,
- rssi_type);
+ wlc_phy_scale_offset_rssi_nphy(
+ pi, 0x0,
+ (s8)
+ fine_digital_offset
+ [core *
+ 2],
+ (core == PHY_CORE_0) ?
+ RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ (result_idx % 2 == 0) ?
+ NPHY_RAIL_I :
+ NPHY_RAIL_Q,
+ rssi_type);
}
}
@@ -22040,87 +22919,87 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
if (CHSPEC_IS2G(pi->radio_chanspec)) {
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
pi->rssical_cache.rssical_radio_regs_2G[0] =
- read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0);
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0);
pi->rssical_cache.rssical_radio_regs_2G[1] =
- read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1);
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1);
} else {
pi->rssical_cache.rssical_radio_regs_2G[0] =
- read_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC |
- RADIO_2056_RX0);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX0);
pi->rssical_cache.rssical_radio_regs_2G[1] =
- read_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC |
- RADIO_2056_RX1);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX1);
}
pi->rssical_cache.rssical_phyregs_2G[0] =
- read_phy_reg(pi, 0x1a6);
+ read_phy_reg(pi, 0x1a6);
pi->rssical_cache.rssical_phyregs_2G[1] =
- read_phy_reg(pi, 0x1ac);
+ read_phy_reg(pi, 0x1ac);
pi->rssical_cache.rssical_phyregs_2G[2] =
- read_phy_reg(pi, 0x1b2);
+ read_phy_reg(pi, 0x1b2);
pi->rssical_cache.rssical_phyregs_2G[3] =
- read_phy_reg(pi, 0x1b8);
+ read_phy_reg(pi, 0x1b8);
pi->rssical_cache.rssical_phyregs_2G[4] =
- read_phy_reg(pi, 0x1a4);
+ read_phy_reg(pi, 0x1a4);
pi->rssical_cache.rssical_phyregs_2G[5] =
- read_phy_reg(pi, 0x1aa);
+ read_phy_reg(pi, 0x1aa);
pi->rssical_cache.rssical_phyregs_2G[6] =
- read_phy_reg(pi, 0x1b0);
+ read_phy_reg(pi, 0x1b0);
pi->rssical_cache.rssical_phyregs_2G[7] =
- read_phy_reg(pi, 0x1b6);
+ read_phy_reg(pi, 0x1b6);
pi->rssical_cache.rssical_phyregs_2G[8] =
- read_phy_reg(pi, 0x1a5);
+ read_phy_reg(pi, 0x1a5);
pi->rssical_cache.rssical_phyregs_2G[9] =
- read_phy_reg(pi, 0x1ab);
+ read_phy_reg(pi, 0x1ab);
pi->rssical_cache.rssical_phyregs_2G[10] =
- read_phy_reg(pi, 0x1b1);
+ read_phy_reg(pi, 0x1b1);
pi->rssical_cache.rssical_phyregs_2G[11] =
- read_phy_reg(pi, 0x1b7);
+ read_phy_reg(pi, 0x1b7);
pi->nphy_rssical_chanspec_2G = pi->radio_chanspec;
} else {
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
pi->rssical_cache.rssical_radio_regs_5G[0] =
- read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0);
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0);
pi->rssical_cache.rssical_radio_regs_5G[1] =
- read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1);
+ read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1);
} else {
pi->rssical_cache.rssical_radio_regs_5G[0] =
- read_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC |
- RADIO_2056_RX0);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX0);
pi->rssical_cache.rssical_radio_regs_5G[1] =
- read_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC |
- RADIO_2056_RX1);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RSSI_MISC |
+ RADIO_2056_RX1);
}
pi->rssical_cache.rssical_phyregs_5G[0] =
- read_phy_reg(pi, 0x1a6);
+ read_phy_reg(pi, 0x1a6);
pi->rssical_cache.rssical_phyregs_5G[1] =
- read_phy_reg(pi, 0x1ac);
+ read_phy_reg(pi, 0x1ac);
pi->rssical_cache.rssical_phyregs_5G[2] =
- read_phy_reg(pi, 0x1b2);
+ read_phy_reg(pi, 0x1b2);
pi->rssical_cache.rssical_phyregs_5G[3] =
- read_phy_reg(pi, 0x1b8);
+ read_phy_reg(pi, 0x1b8);
pi->rssical_cache.rssical_phyregs_5G[4] =
- read_phy_reg(pi, 0x1a4);
+ read_phy_reg(pi, 0x1a4);
pi->rssical_cache.rssical_phyregs_5G[5] =
- read_phy_reg(pi, 0x1aa);
+ read_phy_reg(pi, 0x1aa);
pi->rssical_cache.rssical_phyregs_5G[6] =
- read_phy_reg(pi, 0x1b0);
+ read_phy_reg(pi, 0x1b0);
pi->rssical_cache.rssical_phyregs_5G[7] =
- read_phy_reg(pi, 0x1b6);
+ read_phy_reg(pi, 0x1b6);
pi->rssical_cache.rssical_phyregs_5G[8] =
- read_phy_reg(pi, 0x1a5);
+ read_phy_reg(pi, 0x1a5);
pi->rssical_cache.rssical_phyregs_5G[9] =
- read_phy_reg(pi, 0x1ab);
+ read_phy_reg(pi, 0x1ab);
pi->rssical_cache.rssical_phyregs_5G[10] =
- read_phy_reg(pi, 0x1b1);
+ read_phy_reg(pi, 0x1b1);
pi->rssical_cache.rssical_phyregs_5G[11] =
- read_phy_reg(pi, 0x1b7);
+ read_phy_reg(pi, 0x1b7);
pi->nphy_rssical_chanspec_5G = pi->radio_chanspec;
}
@@ -22129,121 +23008,287 @@ static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi)
wlc_phy_clip_det_nphy(pi, 1, clip_state);
}
-static void wlc_phy_restore_rssical_nphy(struct brcms_phy *pi)
+static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type)
{
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (pi->nphy_rssical_chanspec_2G == 0)
- return;
+ s32 target_code;
+ u16 classif_state;
+ u16 clip_state[2];
+ u16 rssi_ctrl_state[2], pd_state[2];
+ u16 rfctrlintc_state[2], rfpdcorerxtx_state[2];
+ u16 rfctrlintc_override_val;
+ u16 clip_off[] = { 0xffff, 0xffff };
+ u16 rf_pd_val, pd_mask, rssi_ctrl_mask;
+ u8 vcm, min_vcm, vcm_tmp[4];
+ u8 vcm_final[4] = { 0, 0, 0, 0 };
+ u8 result_idx, ctr;
+ s32 poll_results[4][4] = {
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0},
+ {0, 0, 0, 0}
+ };
+ s32 poll_miniq[4][2] = {
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0}
+ };
+ s32 min_d, curr_d;
+ s32 fine_digital_offset[4];
+ s32 poll_results_min[4] = { 0, 0, 0, 0 };
+ s32 min_poll;
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0,
- RADIO_2057_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_2G[0]);
- mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1,
- RADIO_2057_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_2G[1]);
- } else {
- mod_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0,
- RADIO_2056_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_2G[0]);
- mod_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1,
- RADIO_2056_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_2G[1]);
+ switch (rssi_type) {
+ case NPHY_RSSI_SEL_NB:
+ target_code = NPHY_RSSICAL_NB_TARGET;
+ break;
+ case NPHY_RSSI_SEL_W1:
+ target_code = NPHY_RSSICAL_W1_TARGET;
+ break;
+ case NPHY_RSSI_SEL_W2:
+ target_code = NPHY_RSSICAL_W2_TARGET;
+ break;
+ default:
+ return;
+ break;
+ }
+
+ classif_state = wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
+ wlc_phy_clip_det_nphy(pi, 0, clip_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_off);
+
+ rf_pd_val = (rssi_type == NPHY_RSSI_SEL_NB) ? 0x6 : 0x4;
+ rfctrlintc_override_val =
+ CHSPEC_IS5G(pi->radio_chanspec) ? 0x140 : 0x110;
+
+ rfctrlintc_state[0] = read_phy_reg(pi, 0x91);
+ rfpdcorerxtx_state[0] = read_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX);
+ write_phy_reg(pi, 0x91, rfctrlintc_override_val);
+ write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rf_pd_val);
+
+ rfctrlintc_state[1] = read_phy_reg(pi, 0x92);
+ rfpdcorerxtx_state[1] = read_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX);
+ write_phy_reg(pi, 0x92, rfctrlintc_override_val);
+ write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rf_pd_val);
+
+ pd_mask = RADIO_2055_NBRSSI_PD | RADIO_2055_WBRSSI_G1_PD |
+ RADIO_2055_WBRSSI_G2_PD;
+ pd_state[0] =
+ read_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC) & pd_mask;
+ pd_state[1] =
+ read_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC) & pd_mask;
+ mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, 0);
+ mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, 0);
+ rssi_ctrl_mask = RADIO_2055_NBRSSI_SEL | RADIO_2055_WBRSSI_G1_SEL |
+ RADIO_2055_WBRSSI_G2_SEL;
+ rssi_ctrl_state[0] =
+ read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE1) & rssi_ctrl_mask;
+ rssi_ctrl_state[1] =
+ read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE2) & rssi_ctrl_mask;
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type);
+
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX,
+ NPHY_RAIL_I, rssi_type);
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX,
+ NPHY_RAIL_Q, rssi_type);
+
+ for (vcm = 0; vcm < 4; vcm++) {
+
+ vcm_tmp[0] = vcm_tmp[1] = vcm_tmp[2] = vcm_tmp[3] = vcm;
+ if (rssi_type != NPHY_RSSI_SEL_W2)
+ wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_tmp);
+
+ wlc_phy_poll_rssi_nphy(pi, rssi_type, &poll_results[vcm][0],
+ NPHY_RSSICAL_NPOLL);
+
+ if ((rssi_type == NPHY_RSSI_SEL_W1)
+ || (rssi_type == NPHY_RSSI_SEL_W2)) {
+ for (ctr = 0; ctr < 2; ctr++)
+ poll_miniq[vcm][ctr] =
+ min(poll_results[vcm][ctr * 2 + 0],
+ poll_results[vcm][ctr * 2 + 1]);
}
+ }
- write_phy_reg(pi, 0x1a6,
- pi->rssical_cache.rssical_phyregs_2G[0]);
- write_phy_reg(pi, 0x1ac,
- pi->rssical_cache.rssical_phyregs_2G[1]);
- write_phy_reg(pi, 0x1b2,
- pi->rssical_cache.rssical_phyregs_2G[2]);
- write_phy_reg(pi, 0x1b8,
- pi->rssical_cache.rssical_phyregs_2G[3]);
- write_phy_reg(pi, 0x1a4,
- pi->rssical_cache.rssical_phyregs_2G[4]);
- write_phy_reg(pi, 0x1aa,
- pi->rssical_cache.rssical_phyregs_2G[5]);
- write_phy_reg(pi, 0x1b0,
- pi->rssical_cache.rssical_phyregs_2G[6]);
- write_phy_reg(pi, 0x1b6,
- pi->rssical_cache.rssical_phyregs_2G[7]);
- write_phy_reg(pi, 0x1a5,
- pi->rssical_cache.rssical_phyregs_2G[8]);
- write_phy_reg(pi, 0x1ab,
- pi->rssical_cache.rssical_phyregs_2G[9]);
- write_phy_reg(pi, 0x1b1,
- pi->rssical_cache.rssical_phyregs_2G[10]);
- write_phy_reg(pi, 0x1b7,
- pi->rssical_cache.rssical_phyregs_2G[11]);
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ min_d = NPHY_RSSICAL_MAXD;
+ min_vcm = 0;
+ min_poll = NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL + 1;
+ for (vcm = 0; vcm < 4; vcm++) {
+ curr_d = abs(((rssi_type == NPHY_RSSI_SEL_NB) ?
+ poll_results[vcm][result_idx] :
+ poll_miniq[vcm][result_idx / 2]) -
+ (target_code * NPHY_RSSICAL_NPOLL));
+ if (curr_d < min_d) {
+ min_d = curr_d;
+ min_vcm = vcm;
+ }
+ if (poll_results[vcm][result_idx] < min_poll)
+ min_poll = poll_results[vcm][result_idx];
+ }
+ vcm_final[result_idx] = min_vcm;
+ poll_results_min[result_idx] = min_poll;
+ }
- } else {
- if (pi->nphy_rssical_chanspec_5G == 0)
- return;
+ if (rssi_type != NPHY_RSSI_SEL_W2)
+ wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_final);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0,
- RADIO_2057_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_5G[0]);
- mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1,
- RADIO_2057_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_5G[1]);
+ for (result_idx = 0; result_idx < 4; result_idx++) {
+ fine_digital_offset[result_idx] =
+ (target_code * NPHY_RSSICAL_NPOLL) -
+ poll_results[vcm_final[result_idx]][result_idx];
+ if (fine_digital_offset[result_idx] < 0) {
+ fine_digital_offset[result_idx] =
+ abs(fine_digital_offset[result_idx]);
+ fine_digital_offset[result_idx] +=
+ (NPHY_RSSICAL_NPOLL / 2);
+ fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL;
+ fine_digital_offset[result_idx] =
+ -fine_digital_offset[result_idx];
} else {
- mod_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0,
- RADIO_2056_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_5G[0]);
- mod_radio_reg(pi,
- RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1,
- RADIO_2056_VCM_MASK,
- pi->rssical_cache.
- rssical_radio_regs_5G[1]);
+ fine_digital_offset[result_idx] +=
+ (NPHY_RSSICAL_NPOLL / 2);
+ fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL;
}
- write_phy_reg(pi, 0x1a6,
- pi->rssical_cache.rssical_phyregs_5G[0]);
- write_phy_reg(pi, 0x1ac,
- pi->rssical_cache.rssical_phyregs_5G[1]);
- write_phy_reg(pi, 0x1b2,
- pi->rssical_cache.rssical_phyregs_5G[2]);
- write_phy_reg(pi, 0x1b8,
- pi->rssical_cache.rssical_phyregs_5G[3]);
- write_phy_reg(pi, 0x1a4,
- pi->rssical_cache.rssical_phyregs_5G[4]);
- write_phy_reg(pi, 0x1aa,
- pi->rssical_cache.rssical_phyregs_5G[5]);
- write_phy_reg(pi, 0x1b0,
- pi->rssical_cache.rssical_phyregs_5G[6]);
- write_phy_reg(pi, 0x1b6,
- pi->rssical_cache.rssical_phyregs_5G[7]);
- write_phy_reg(pi, 0x1a5,
- pi->rssical_cache.rssical_phyregs_5G[8]);
- write_phy_reg(pi, 0x1ab,
- pi->rssical_cache.rssical_phyregs_5G[9]);
- write_phy_reg(pi, 0x1b1,
- pi->rssical_cache.rssical_phyregs_5G[10]);
- write_phy_reg(pi, 0x1b7,
- pi->rssical_cache.rssical_phyregs_5G[11]);
+ if (poll_results_min[result_idx] ==
+ NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL)
+ fine_digital_offset[result_idx] =
+ (target_code - NPHY_RSSICAL_MAXREAD - 1);
+
+ wlc_phy_scale_offset_rssi_nphy(pi, 0x0,
+ (s8)
+ fine_digital_offset[result_idx],
+ (result_idx / 2 ==
+ 0) ? RADIO_MIMO_CORESEL_CORE1 :
+ RADIO_MIMO_CORESEL_CORE2,
+ (result_idx % 2 ==
+ 0) ? NPHY_RAIL_I : NPHY_RAIL_Q,
+ rssi_type);
+ }
+
+ mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, pd_state[0]);
+ mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, pd_state[1]);
+ if (rssi_ctrl_state[0] == RADIO_2055_NBRSSI_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_NB);
+ else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G1_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_W1);
+ else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G2_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_W2);
+ else
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1,
+ NPHY_RSSI_SEL_W2);
+ if (rssi_ctrl_state[1] == RADIO_2055_NBRSSI_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_NB);
+ else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G1_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_W1);
+ else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G2_SEL)
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_W2);
+ else
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2,
+ NPHY_RSSI_SEL_W2);
+
+ wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, rssi_type);
+
+ write_phy_reg(pi, 0x91, rfctrlintc_state[0]);
+ write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rfpdcorerxtx_state[0]);
+ write_phy_reg(pi, 0x92, rfctrlintc_state[1]);
+ write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rfpdcorerxtx_state[1]);
+
+ wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state);
+ wlc_phy_clip_det_nphy(pi, 1, clip_state);
+
+ wlc_phy_resetcca_nphy(pi);
+}
+
+void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi)
+{
+ if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ wlc_phy_rssi_cal_nphy_rev3(pi);
+ } else {
+ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_NB);
+ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W1);
+ wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W2);
}
}
+int
+wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh)
+{
+ s16 rxpwr, rxpwr0, rxpwr1;
+ s16 phyRx0_l, phyRx2_l;
+
+ rxpwr = 0;
+ rxpwr0 = rxh->PhyRxStatus_1 & PRXS1_nphy_PWR0_MASK;
+ rxpwr1 = (rxh->PhyRxStatus_1 & PRXS1_nphy_PWR1_MASK) >> 8;
+
+ if (rxpwr0 > 127)
+ rxpwr0 -= 256;
+ if (rxpwr1 > 127)
+ rxpwr1 -= 256;
+
+ phyRx0_l = rxh->PhyRxStatus_0 & 0x00ff;
+ phyRx2_l = rxh->PhyRxStatus_2 & 0x00ff;
+ if (phyRx2_l > 127)
+ phyRx2_l -= 256;
+
+ if (((rxpwr0 == 16) || (rxpwr0 == 32))) {
+ rxpwr0 = rxpwr1;
+ rxpwr1 = phyRx2_l;
+ }
+
+ if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MAX)
+ rxpwr = (rxpwr0 > rxpwr1) ? rxpwr0 : rxpwr1;
+ else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MIN)
+ rxpwr = (rxpwr0 < rxpwr1) ? rxpwr0 : rxpwr1;
+ else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_AVG)
+ rxpwr = (rxpwr0 + rxpwr1) >> 1;
+
+ return rxpwr;
+}
+
+static void
+wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, struct cordic_iq *tone_buf,
+ u16 num_samps)
+{
+ u16 t;
+ u32 *data_buf = NULL;
+
+ data_buf = kmalloc(sizeof(u32) * num_samps, GFP_ATOMIC);
+ if (data_buf == NULL)
+ return;
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
+
+ for (t = 0; t < num_samps; t++)
+ data_buf[t] = ((((unsigned int)tone_buf[t].i) & 0x3ff) << 10) |
+ (((unsigned int)tone_buf[t].q) & 0x3ff);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SAMPLEPLAY, num_samps, 0, 32,
+ data_buf);
+
+ kfree(data_buf);
+
+ if (pi->phyhang_avoid)
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+}
+
static u16
wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
u8 dac_test_mode)
{
u8 phy_bw, is_phybw40;
u16 num_samps, t, spur;
- fixed theta = 0, rot = 0;
+ s32 theta = 0, rot = 0;
u32 tbl_len;
- cs32 *tone_buf = NULL;
+ struct cordic_iq *tone_buf = NULL;
is_phybw40 = CHSPEC_IS40(pi->radio_chanspec);
phy_bw = (is_phybw40 == 1) ? 40 : 20;
@@ -22258,18 +23303,17 @@ wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
tbl_len = (phy_bw << 1);
}
- tone_buf = kmalloc(sizeof(cs32) * tbl_len, GFP_ATOMIC);
- if (tone_buf == NULL) {
+ tone_buf = kmalloc(sizeof(struct cordic_iq) * tbl_len, GFP_ATOMIC);
+ if (tone_buf == NULL)
return 0;
- }
num_samps = (u16) tbl_len;
- rot = FIXED((f_kHz * 36) / phy_bw) / 100;
+ rot = ((f_kHz * 36) / phy_bw) / 100;
theta = 0;
for (t = 0; t < num_samps; t++) {
- wlc_phy_cordic(theta, &tone_buf[t]);
+ tone_buf[t] = cordic_calc_iq(theta);
theta += rot;
@@ -22284,54 +23328,6 @@ wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
return num_samps;
}
-int
-wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
- u8 iqmode, u8 dac_test_mode, bool modify_bbmult)
-{
- u16 num_samps;
- u16 loops = 0xffff;
- u16 wait = 0;
-
- num_samps =
- wlc_phy_gen_load_samples_nphy(pi, f_kHz, max_val, dac_test_mode);
- if (num_samps == 0) {
- return -EBADE;
- }
-
- wlc_phy_runsamples_nphy(pi, num_samps, loops, wait, iqmode,
- dac_test_mode, modify_bbmult);
-
- return 0;
-}
-
-static void
-wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, cs32 *tone_buf,
- u16 num_samps)
-{
- u16 t;
- u32 *data_buf = NULL;
-
- data_buf = kmalloc(sizeof(u32) * num_samps, GFP_ATOMIC);
- if (data_buf == NULL) {
- return;
- }
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- for (t = 0; t < num_samps; t++) {
- data_buf[t] = ((((unsigned int)tone_buf[t].i) & 0x3ff) << 10) |
- (((unsigned int)tone_buf[t].q) & 0x3ff);
- }
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SAMPLEPLAY, num_samps, 0, 32,
- data_buf);
-
- kfree(data_buf);
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-}
-
static void
wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops,
u16 wait, u8 iqmode, u8 dac_test_mode,
@@ -22356,22 +23352,24 @@ wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops,
lpf_bw_ctl_override4 = read_phy_reg(pi, 0x343) & (0x1 << 7);
if (lpf_bw_ctl_override3 | lpf_bw_ctl_override4) {
lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) &
- (0x7 << 8);
+ (0x7 << 8);
lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) &
- (0x7 << 8);
+ (0x7 << 8);
} else {
- wlc_phy_rfctrl_override_nphy_rev7(pi,
- (0x1 << 7),
- wlc_phy_read_lpf_bw_ctl_nphy
- (pi, 0), 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ wlc_phy_read_lpf_bw_ctl_nphy
+ (pi,
+ 0), 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
pi->nphy_sample_play_lpf_bw_ctl_ovr = true;
lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) &
- (0x7 << 8);
+ (0x7 << 8);
lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) &
- (0x7 << 8);
+ (0x7 << 8);
}
}
@@ -22380,7 +23378,7 @@ wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops,
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16,
&bb_mult);
pi->nphy_bb_mult_save =
- BB_MULT_VALID_MASK | (bb_mult & BB_MULT_MASK);
+ BB_MULT_VALID_MASK | (bb_mult & BB_MULT_MASK);
}
if (modify_bbmult) {
@@ -22395,11 +23393,11 @@ wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops,
write_phy_reg(pi, 0xc6, num_samps - 1);
- if (loops != 0xffff) {
+ if (loops != 0xffff)
write_phy_reg(pi, 0xc4, loops - 1);
- } else {
+ else
write_phy_reg(pi, 0xc4, loops);
- }
+
write_phy_reg(pi, 0xc5, wait);
orig_RfseqCoreActv = read_phy_reg(pi, 0xa1);
@@ -22420,6 +23418,25 @@ wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops,
write_phy_reg(pi, 0xa1, orig_RfseqCoreActv);
}
+int
+wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val,
+ u8 iqmode, u8 dac_test_mode, bool modify_bbmult)
+{
+ u16 num_samps;
+ u16 loops = 0xffff;
+ u16 wait = 0;
+
+ num_samps = wlc_phy_gen_load_samples_nphy(pi, f_kHz, max_val,
+ dac_test_mode);
+ if (num_samps == 0)
+ return -EBADE;
+
+ wlc_phy_runsamples_nphy(pi, num_samps, loops, wait, iqmode,
+ dac_test_mode, modify_bbmult);
+
+ return 0;
+}
+
void wlc_phy_stopplayback_nphy(struct brcms_phy *pi)
{
u16 playback_status;
@@ -22429,13 +23446,11 @@ void wlc_phy_stopplayback_nphy(struct brcms_phy *pi)
wlc_phy_stay_in_carriersearch_nphy(pi, true);
playback_status = read_phy_reg(pi, 0xc7);
- if (playback_status & 0x1) {
+ if (playback_status & 0x1)
or_phy_reg(pi, 0xc3, NPHY_sampleCmd_STOP);
- } else if (playback_status & 0x2) {
-
+ else if (playback_status & 0x2)
and_phy_reg(pi, 0xc2,
(u16) ~NPHY_iqloCalCmdGctl_IQLO_CAL_EN);
- }
and_phy_reg(pi, 0xc3, (u16) ~(0x1 << 2));
@@ -22450,10 +23465,11 @@ void wlc_phy_stopplayback_nphy(struct brcms_phy *pi)
if (NREV_IS(pi->pubpi.phy_rev, 7) || NREV_GE(pi->pubpi.phy_rev, 8)) {
if (pi->nphy_sample_play_lpf_bw_ctl_ovr) {
- wlc_phy_rfctrl_override_nphy_rev7(pi,
- (0x1 << 7),
- 0, 0, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ 0, 0, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
pi->nphy_sample_play_lpf_bw_ctl_ovr = false;
}
}
@@ -22462,6 +23478,47 @@ void wlc_phy_stopplayback_nphy(struct brcms_phy *pi)
wlc_phy_stay_in_carriersearch_nphy(pi, false);
}
+static u32 *brcms_phy_get_tx_pwrctrl_tbl(struct brcms_phy *pi)
+{
+ u32 *tx_pwrctrl_tbl = NULL;
+ uint phyrev = pi->pubpi.phy_rev;
+
+ if (PHY_IPA(pi)) {
+ tx_pwrctrl_tbl =
+ wlc_phy_get_ipa_gaintbl_nphy(pi);
+ } else {
+ if (CHSPEC_IS5G(pi->radio_chanspec)) {
+ if (NREV_IS(phyrev, 3))
+ tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev3;
+ else if (NREV_IS(phyrev, 4))
+ tx_pwrctrl_tbl =
+ (pi->srom_fem5g.extpagain == 3) ?
+ nphy_tpc_5GHz_txgain_HiPwrEPA :
+ nphy_tpc_5GHz_txgain_rev4;
+ else
+ tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev5;
+ } else {
+ if (NREV_GE(phyrev, 7)) {
+ if (pi->pubpi.radiorev == 3)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev3;
+ else if (pi->pubpi.radiorev == 5)
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_epa_2057rev5;
+ } else {
+ if (NREV_GE(phyrev, 5) &&
+ (pi->srom_fem2g.extpagain == 3))
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_HiPwrEPA;
+ else
+ tx_pwrctrl_tbl =
+ nphy_tpc_txgain_rev3;
+ }
+ }
+ }
+ return tx_pwrctrl_tbl;
+}
+
struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi)
{
u16 base_idx[2], curr_gain[2];
@@ -22482,33 +23539,33 @@ struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi)
for (core_no = 0; core_no < 2; core_no++) {
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
target_gain.ipa[core_no] =
- curr_gain[core_no] & 0x0007;
+ curr_gain[core_no] & 0x0007;
target_gain.pad[core_no] =
- ((curr_gain[core_no] & 0x00F8) >> 3);
+ ((curr_gain[core_no] & 0x00F8) >> 3);
target_gain.pga[core_no] =
- ((curr_gain[core_no] & 0x0F00) >> 8);
+ ((curr_gain[core_no] & 0x0F00) >> 8);
target_gain.txgm[core_no] =
- ((curr_gain[core_no] & 0x7000) >> 12);
+ ((curr_gain[core_no] & 0x7000) >> 12);
target_gain.txlpf[core_no] =
- ((curr_gain[core_no] & 0x8000) >> 15);
+ ((curr_gain[core_no] & 0x8000) >> 15);
} else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
target_gain.ipa[core_no] =
- curr_gain[core_no] & 0x000F;
+ curr_gain[core_no] & 0x000F;
target_gain.pad[core_no] =
- ((curr_gain[core_no] & 0x00F0) >> 4);
+ ((curr_gain[core_no] & 0x00F0) >> 4);
target_gain.pga[core_no] =
- ((curr_gain[core_no] & 0x0F00) >> 8);
+ ((curr_gain[core_no] & 0x0F00) >> 8);
target_gain.txgm[core_no] =
- ((curr_gain[core_no] & 0x7000) >> 12);
+ ((curr_gain[core_no] & 0x7000) >> 12);
} else {
target_gain.ipa[core_no] =
- curr_gain[core_no] & 0x0003;
+ curr_gain[core_no] & 0x0003;
target_gain.pad[core_no] =
- ((curr_gain[core_no] & 0x000C) >> 2);
+ ((curr_gain[core_no] & 0x000C) >> 2);
target_gain.pga[core_no] =
- ((curr_gain[core_no] & 0x0070) >> 4);
+ ((curr_gain[core_no] & 0x0070) >> 4);
target_gain.txgm[core_no] =
- ((curr_gain[core_no] & 0x0380) >> 7);
+ ((curr_gain[core_no] & 0x0380) >> 7);
}
}
} else {
@@ -22518,96 +23575,60 @@ struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi)
base_idx[1] = (read_phy_reg(pi, 0x1ee) >> 8) & 0x7f;
for (core_no = 0; core_no < 2; core_no++) {
if (NREV_GE(phyrev, 3)) {
- if (PHY_IPA(pi)) {
- tx_pwrctrl_tbl =
- wlc_phy_get_ipa_gaintbl_nphy(pi);
- } else {
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- if (NREV_IS(phyrev, 3)) {
- tx_pwrctrl_tbl =
- nphy_tpc_5GHz_txgain_rev3;
- } else if (NREV_IS(phyrev, 4)) {
- tx_pwrctrl_tbl =
- (pi->srom_fem5g.
- extpagain ==
- 3) ?
- nphy_tpc_5GHz_txgain_HiPwrEPA
- :
- nphy_tpc_5GHz_txgain_rev4;
- } else {
- tx_pwrctrl_tbl =
- nphy_tpc_5GHz_txgain_rev5;
- }
- } else {
- if (NREV_GE(phyrev, 7)) {
- if (pi->pubpi.
- radiorev == 3) {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_epa_2057rev3;
- } else if (pi->pubpi.
- radiorev ==
- 5) {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_epa_2057rev5;
- }
-
- } else {
- if (NREV_GE(phyrev, 5)
- && (pi->srom_fem2g.
- extpagain ==
- 3)) {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_HiPwrEPA;
- } else {
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_rev3;
- }
- }
- }
- }
+ tx_pwrctrl_tbl =
+ brcms_phy_get_tx_pwrctrl_tbl(pi);
if (NREV_GE(phyrev, 7)) {
target_gain.ipa[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 16) & 0x7;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 16) & 0x7;
target_gain.pad[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 19) & 0x1f;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 19) & 0x1f;
target_gain.pga[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 24) & 0xf;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 24) & 0xf;
target_gain.txgm[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 28) & 0x7;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 28) & 0x7;
target_gain.txlpf[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 31) & 0x1;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 31) & 0x1;
} else {
target_gain.ipa[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 16) & 0xf;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 16) & 0xf;
target_gain.pad[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 20) & 0xf;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 20) & 0xf;
target_gain.pga[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 24) & 0xf;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 24) & 0xf;
target_gain.txgm[core_no] =
- (tx_pwrctrl_tbl[base_idx[core_no]]
- >> 28) & 0x7;
+ (tx_pwrctrl_tbl
+ [base_idx[core_no]]
+ >> 28) & 0x7;
}
} else {
target_gain.ipa[core_no] =
- (nphy_tpc_txgain[base_idx[core_no]] >> 16) &
- 0x3;
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 16) & 0x3;
target_gain.pad[core_no] =
- (nphy_tpc_txgain[base_idx[core_no]] >> 18) &
- 0x3;
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 18) & 0x3;
target_gain.pga[core_no] =
- (nphy_tpc_txgain[base_idx[core_no]] >> 20) &
- 0x7;
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 20) & 0x7;
target_gain.txgm[core_no] =
- (nphy_tpc_txgain[base_idx[core_no]] >> 23) &
- 0x7;
+ (nphy_tpc_txgain[base_idx[core_no]] >>
+ 23) & 0x7;
}
}
}
@@ -22626,26 +23647,23 @@ wlc_phy_iqcal_gainparams_nphy(struct brcms_phy *pi, u16 core_no,
u8 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0);
if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
params->txlpf = target_gain.txlpf[core_no];
- }
+
params->txgm = target_gain.txgm[core_no];
params->pga = target_gain.pga[core_no];
params->pad = target_gain.pad[core_no];
params->ipa = target_gain.ipa[core_no];
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
params->cal_gain =
- ((params->txlpf << 15) | (params->
- txgm << 12) | (params->
- pga << 8) |
- (params->pad << 3) | (params->ipa));
- } else {
+ ((params->txlpf << 15) | (params->txgm << 12) |
+ (params->pga << 8) |
+ (params->pad << 3) | (params->ipa));
+ else
params->cal_gain =
- ((params->txgm << 12) | (params->
- pga << 8) | (params->
- pad << 4) |
- (params->ipa));
- }
+ ((params->txgm << 12) | (params->pga << 8) |
+ (params->pad << 4) | (params->ipa));
+
params->ncorr[0] = 0x79;
params->ncorr[1] = 0x79;
params->ncorr[2] = 0x79;
@@ -22654,9 +23672,8 @@ wlc_phy_iqcal_gainparams_nphy(struct brcms_phy *pi, u16 core_no,
} else {
gain_index = ((target_gain.pad[core_no] << 0) |
- (target_gain.pga[core_no] << 4) | (target_gain.
- txgm[core_no]
- << 8));
+ (target_gain.pga[core_no] << 4) |
+ (target_gain.txgm[core_no] << 8));
idx = -1;
for (k = 0; k < NPHY_IQCAL_NUMGAINS; k++) {
@@ -22688,37 +23705,39 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
for (core = 0; core <= 1; core++) {
pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TX_SSI_MASTER);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MASTER);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- IQCAL_VCM_HG);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_VCM_HG);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- IQCAL_IDAC);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ IQCAL_IDAC);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_VCM);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] = 0;
pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TX_SSI_MUX);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TX_SSI_MUX);
if (pi->pubpi.radiorev != 5)
pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TSSIA);
+ READ_RADIO_REG3(pi, RADIO_2057, TX,
+ core,
+ TSSIA);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TSSI_MISC1);
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TSSI_MISC1);
if (CHSPEC_IS5G(pi->radio_chanspec)) {
WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
@@ -22734,19 +23753,15 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
if (pi->use_int_tx_iqlo_cal_nphy) {
WRITE_RADIO_REG3(pi, RADIO_2057, TX,
core, TX_SSI_MUX, 0x4);
- if (!
- (pi->
- internal_tx_iqlo_cal_tapoff_intpa_nphy)) {
-
+ if (!(pi->
+ internal_tx_iqlo_cal_tapoff_intpa_nphy))
WRITE_RADIO_REG3(pi, RADIO_2057,
TX, core,
TSSIA, 0x31);
- } else {
-
+ else
WRITE_RADIO_REG3(pi, RADIO_2057,
TX, core,
TSSIA, 0x21);
- }
}
WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
TSSI_MISC1, 0x00);
@@ -22767,19 +23782,15 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
WRITE_RADIO_REG3(pi, RADIO_2057, TX,
core, TX_SSI_MUX,
0x06);
- if (!
- (pi->
- internal_tx_iqlo_cal_tapoff_intpa_nphy)) {
-
+ if (!(pi->
+ internal_tx_iqlo_cal_tapoff_intpa_nphy))
WRITE_RADIO_REG3(pi, RADIO_2057,
TX, core,
TSSIG, 0x31);
- } else {
-
+ else
WRITE_RADIO_REG3(pi, RADIO_2057,
TX, core,
TSSIG, 0x21);
- }
}
WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
TSSI_MISC1, 0x00);
@@ -22789,58 +23800,62 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
for (core = 0; core <= 1; core++) {
jtag_core =
- (core ==
- PHY_CORE_0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
+ (core ==
+ PHY_CORE_0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] =
- read_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MASTER |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MASTER |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] =
- read_radio_reg(pi,
- RADIO_2056_TX_IQCAL_VCM_HG |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_VCM_HG |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] =
- read_radio_reg(pi,
- RADIO_2056_TX_IQCAL_IDAC |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_IQCAL_IDAC |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] =
- read_radio_reg(pi,
- RADIO_2056_TX_TSSI_VCM | jtag_core);
+ read_radio_reg(
+ pi,
+ RADIO_2056_TX_TSSI_VCM |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] =
- read_radio_reg(pi,
- RADIO_2056_TX_TX_AMP_DET |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TX_AMP_DET |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] =
- read_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MUX |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TX_SSI_MUX |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] =
- read_radio_reg(pi, RADIO_2056_TX_TSSIA | jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSIA | jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] =
- read_radio_reg(pi, RADIO_2056_TX_TSSIG | jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSIG | jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] =
- read_radio_reg(pi,
- RADIO_2056_TX_TSSI_MISC1 |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC1 |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 9] =
- read_radio_reg(pi,
- RADIO_2056_TX_TSSI_MISC2 |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC2 |
+ jtag_core);
pi->tx_rx_cal_radio_saveregs[(core * 11) + 10] =
- read_radio_reg(pi,
- RADIO_2056_TX_TSSI_MISC3 |
- jtag_core);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TSSI_MISC3 |
+ jtag_core);
if (CHSPEC_IS5G(pi->radio_chanspec)) {
write_radio_reg(pi,
@@ -22860,16 +23875,18 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
jtag_core, 0x00);
if (PHY_IPA(pi)) {
- write_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MUX
- | jtag_core, 0x4);
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x4);
write_radio_reg(pi,
RADIO_2056_TX_TSSIA |
jtag_core, 0x1);
} else {
- write_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MUX
- | jtag_core, 0x00);
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x00);
write_radio_reg(pi,
RADIO_2056_TX_TSSIA |
jtag_core, 0x2f);
@@ -22909,26 +23926,27 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
if (PHY_IPA(pi)) {
- write_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MUX
- | jtag_core, 0x06);
- if (NREV_LT(pi->pubpi.phy_rev, 5)) {
-
- write_radio_reg(pi,
- RADIO_2056_TX_TSSIG
- | jtag_core,
- 0x11);
- } else {
-
- write_radio_reg(pi,
- RADIO_2056_TX_TSSIG
- | jtag_core,
- 0x1);
- }
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x06);
+ if (NREV_LT(pi->pubpi.phy_rev, 5))
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TSSIG
+ | jtag_core,
+ 0x11);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TSSIG
+ | jtag_core,
+ 0x1);
} else {
- write_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MUX
- | jtag_core, 0x00);
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TX_SSI_MUX
+ | jtag_core, 0x00);
write_radio_reg(pi,
RADIO_2056_TX_TSSIG |
jtag_core, 0x20);
@@ -22948,23 +23966,23 @@ static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi)
} else {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1);
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1);
write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x29);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2);
+ read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2);
write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x54);
pi->tx_rx_cal_radio_saveregs[2] =
- read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1);
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1);
write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x29);
pi->tx_rx_cal_radio_saveregs[3] =
- read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2);
+ read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2);
write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x54);
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1);
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1);
pi->tx_rx_cal_radio_saveregs[5] =
- read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2);
+ read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2);
if ((read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand) ==
0) {
@@ -23025,11 +24043,8 @@ static void wlc_phy_txcal_radio_cleanup_nphy(struct brcms_phy *pi)
if (pi->pubpi.radiorev != 5)
WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
TSSIA,
- pi->
- tx_rx_cal_radio_saveregs[(core
- *
- 11) +
- 6]);
+ pi->tx_rx_cal_radio_saveregs
+ [(core * 11) + 6]);
WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG,
pi->
@@ -23043,9 +24058,8 @@ static void wlc_phy_txcal_radio_cleanup_nphy(struct brcms_phy *pi)
}
} else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
for (core = 0; core <= 1; core++) {
- jtag_core =
- (core ==
- PHY_CORE_0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
+ jtag_core = (core == PHY_CORE_0) ?
+ RADIO_2056_TX0 : RADIO_2056_TX1;
write_radio_reg(pi,
RADIO_2056_TX_TX_SSI_MASTER | jtag_core,
@@ -23171,23 +24185,22 @@ static void wlc_phy_txcal_physetup_nphy(struct brcms_phy *pi)
pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0x91);
pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0x92);
- if (!(pi->use_int_tx_iqlo_cal_nphy)) {
-
- wlc_phy_rfctrlintc_override_nphy(pi,
- NPHY_RfctrlIntc_override_PA,
- 1,
- RADIO_MIMO_CORESEL_CORE1
- |
- RADIO_MIMO_CORESEL_CORE2);
- } else {
-
- wlc_phy_rfctrlintc_override_nphy(pi,
- NPHY_RfctrlIntc_override_PA,
- 0,
- RADIO_MIMO_CORESEL_CORE1
- |
- RADIO_MIMO_CORESEL_CORE2);
- }
+ if (!(pi->use_int_tx_iqlo_cal_nphy))
+ wlc_phy_rfctrlintc_override_nphy(
+ pi,
+ NPHY_RfctrlIntc_override_PA,
+ 1,
+ RADIO_MIMO_CORESEL_CORE1
+ |
+ RADIO_MIMO_CORESEL_CORE2);
+ else
+ wlc_phy_rfctrlintc_override_nphy(
+ pi,
+ NPHY_RfctrlIntc_override_PA,
+ 0,
+ RADIO_MIMO_CORESEL_CORE1
+ |
+ RADIO_MIMO_CORESEL_CORE2);
wlc_phy_rfctrlintc_override_nphy(pi,
NPHY_RfctrlIntc_override_TRSW,
@@ -23205,12 +24218,13 @@ static void wlc_phy_txcal_physetup_nphy(struct brcms_phy *pi)
0x29b, (0x1 << 0), (0) << 0);
if (NREV_IS(pi->pubpi.phy_rev, 7)
- || NREV_GE(pi->pubpi.phy_rev, 8)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7),
- wlc_phy_read_lpf_bw_ctl_nphy
- (pi, 0), 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- }
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7),
+ wlc_phy_read_lpf_bw_ctl_nphy
+ (pi,
+ 0), 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
if (pi->use_int_tx_iqlo_cal_nphy
&& !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) {
@@ -23221,25 +24235,30 @@ static void wlc_phy_txcal_physetup_nphy(struct brcms_phy *pi)
1 << 4);
if (CHSPEC_IS2G(pi->radio_chanspec)) {
- mod_radio_reg(pi,
- RADIO_2057_PAD2G_TUNE_PUS_CORE0,
- 1, 0);
- mod_radio_reg(pi,
- RADIO_2057_PAD2G_TUNE_PUS_CORE1,
- 1, 0);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE0,
+ 1, 0);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE1,
+ 1, 0);
} else {
- mod_radio_reg(pi,
- RADIO_2057_IPA5G_CASCOFFV_PU_CORE0,
- 1, 0);
- mod_radio_reg(pi,
- RADIO_2057_IPA5G_CASCOFFV_PU_CORE1,
- 1, 0);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE0,
+ 1, 0);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE1,
+ 1, 0);
}
} else if (NREV_GE(pi->pubpi.phy_rev, 8)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi,
- (0x1 << 3), 0,
- 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 3), 0,
+ 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
}
}
} else {
@@ -23302,11 +24321,11 @@ static void wlc_phy_txcal_phycleanup_nphy(struct brcms_phy *pi)
write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]);
if (NREV_IS(pi->pubpi.phy_rev, 7)
- || NREV_GE(pi->pubpi.phy_rev, 8)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7), 0, 0,
- 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- }
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7), 0, 0,
+ 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
wlc_phy_resetcca_nphy(pi);
@@ -23315,28 +24334,33 @@ static void wlc_phy_txcal_phycleanup_nphy(struct brcms_phy *pi)
if (NREV_IS(pi->pubpi.phy_rev, 7)) {
if (CHSPEC_IS2G(pi->radio_chanspec)) {
- mod_radio_reg(pi,
- RADIO_2057_PAD2G_TUNE_PUS_CORE0,
- 1, 1);
- mod_radio_reg(pi,
- RADIO_2057_PAD2G_TUNE_PUS_CORE1,
- 1, 1);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE0,
+ 1, 1);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_PAD2G_TUNE_PUS_CORE1,
+ 1, 1);
} else {
- mod_radio_reg(pi,
- RADIO_2057_IPA5G_CASCOFFV_PU_CORE0,
- 1, 1);
- mod_radio_reg(pi,
- RADIO_2057_IPA5G_CASCOFFV_PU_CORE1,
- 1, 1);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE0,
+ 1, 1);
+ mod_radio_reg(
+ pi,
+ RADIO_2057_IPA5G_CASCOFFV_PU_CORE1,
+ 1, 1);
}
mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4,
0);
} else if (NREV_GE(pi->pubpi.phy_rev, 8)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi,
- (0x1 << 3), 0,
- 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 3), 0,
+ 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
}
}
} else {
@@ -23356,10 +24380,6 @@ static void wlc_phy_txcal_phycleanup_nphy(struct brcms_phy *pi)
}
}
-#define NPHY_CAL_TSSISAMPS 64
-#define NPHY_TEST_TONE_FREQ_40MHz 4000
-#define NPHY_TEST_TONE_FREQ_20MHz 2500
-
void
wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps)
{
@@ -23379,8 +24399,8 @@ wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps)
idle_tssi[1] = (temp <= 31) ? temp : (temp - 64);
tssi_type =
- CHSPEC_IS5G(pi->radio_chanspec) ?
- (u8)NPHY_RSSI_SEL_TSSI_5G : (u8)NPHY_RSSI_SEL_TSSI_2G;
+ CHSPEC_IS5G(pi->radio_chanspec) ?
+ (u8)NPHY_RSSI_SEL_TSSI_5G : (u8)NPHY_RSSI_SEL_TSSI_2G;
wlc_phy_poll_rssi_nphy(pi, tssi_type, rssi_buf, num_samps);
@@ -23390,17 +24410,15 @@ wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps)
pwrindex[0] = idle_tssi[0] - tssival[0] + 64;
pwrindex[1] = idle_tssi[1] - tssival[1] + 64;
- if (pwrindex[0] < 0) {
+ if (pwrindex[0] < 0)
pwrindex[0] = 0;
- } else if (pwrindex[0] > 63) {
+ else if (pwrindex[0] > 63)
pwrindex[0] = 63;
- }
- if (pwrindex[1] < 0) {
+ if (pwrindex[1] < 0)
pwrindex[1] = 0;
- } else if (pwrindex[1] > 63) {
+ else if (pwrindex[1] > 63)
pwrindex[1] = 63;
- }
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 1,
(u32) pwrindex[0], 32, &qdBm_pwrbuf[0]);
@@ -23408,326 +24426,1241 @@ wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps)
(u32) pwrindex[1], 32, &qdBm_pwrbuf[1]);
}
-static void wlc_phy_internal_cal_txgain_nphy(struct brcms_phy *pi)
+static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core)
{
- u16 txcal_gain[2];
+ int index;
+ u32 bbmult_scale;
+ u16 bbmult;
+ u16 tblentry;
- pi->nphy_txcal_pwr_idx[0] = pi->nphy_cal_orig_pwr_idx[0];
- pi->nphy_txcal_pwr_idx[1] = pi->nphy_cal_orig_pwr_idx[0];
- wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true);
- wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true);
+ struct nphy_txiqcal_ladder ladder_lo[] = {
+ {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
+ {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5},
+ {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7}
+ };
- wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
- txcal_gain);
+ struct nphy_txiqcal_ladder ladder_iq[] = {
+ {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
+ {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1},
+ {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7}
+ };
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F40;
- txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F40;
- } else {
- txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F60;
- txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F60;
+ bbmult = (core == PHY_CORE_0) ?
+ ((pi->nphy_txcal_bbmult >> 8) & 0xff) :
+ (pi->nphy_txcal_bbmult & 0xff);
+
+ for (index = 0; index < 18; index++) {
+ bbmult_scale = ladder_lo[index].percent * bbmult;
+ bbmult_scale /= 100;
+
+ tblentry =
+ ((bbmult_scale & 0xff) << 8) | ladder_lo[index].g_env;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index, 16,
+ &tblentry);
+
+ bbmult_scale = ladder_iq[index].percent * bbmult;
+ bbmult_scale /= 100;
+
+ tblentry =
+ ((bbmult_scale & 0xff) << 8) | ladder_iq[index].g_env;
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index + 32,
+ 16, &tblentry);
}
+}
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
- txcal_gain);
+static u8 wlc_phy_txpwr_idx_cur_get_nphy(struct brcms_phy *pi, u8 core)
+{
+ u16 tmp;
+ tmp = read_phy_reg(pi, ((core == PHY_CORE_0) ? 0x1ed : 0x1ee));
+
+ tmp = (tmp & (0x7f << 8)) >> 8;
+ return (u8) tmp;
}
-static void wlc_phy_precal_txgain_nphy(struct brcms_phy *pi)
+static void
+wlc_phy_txpwr_idx_cur_set_nphy(struct brcms_phy *pi, u8 idx0, u8 idx1)
{
- bool save_bbmult = false;
- u8 txcal_index_2057_rev5n7 = 0;
- u8 txcal_index_2057_rev3n4n6 = 10;
+ mod_phy_reg(pi, 0x1e7, (0x7f << 0), idx0);
+
+ if (NREV_GT(pi->pubpi.phy_rev, 1))
+ mod_phy_reg(pi, 0x222, (0xff << 0), idx1);
+}
+
+static u16 wlc_phy_ipa_get_bbmult_nphy(struct brcms_phy *pi)
+{
+ u16 m0m1;
+
+ wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1);
+
+ return m0m1;
+}
+
+static void wlc_phy_ipa_set_bbmult_nphy(struct brcms_phy *pi, u8 m0, u8 m1)
+{
+ u16 m0m1 = (u16) ((m0 << 8) | m1);
+
+ wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m0m1);
+ wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &m0m1);
+}
+
+static void
+wlc_phy_papd_cal_setup_nphy(struct brcms_phy *pi,
+ struct nphy_papd_restore_state *state, u8 core)
+{
+ s32 tone_freq;
+ u8 off_core;
+ u16 mixgain = 0;
+
+ off_core = core ^ 0x1;
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7),
+ wlc_phy_read_lpf_bw_ctl_nphy
+ (pi,
+ 0), 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev == 5)
+ mixgain = (core == 0) ? 0x20 : 0x00;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ mixgain = 0x00;
+ else if ((pi->pubpi.radiorev <= 4)
+ || (pi->pubpi.radiorev == 6))
+ mixgain = 0x00;
+ } else {
+ if ((pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ mixgain = 0x50;
+ else if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ mixgain = 0x0;
+ }
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11),
+ mixgain, (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_tx_pu,
+ 1, (1 << core), 0);
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_tx_pu,
+ 0, (1 << off_core), 0);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5),
+ 0, (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0,
+ (1 << core), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7);
+ state->afeoverride[core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5);
+ state->afectrl[off_core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa7 : 0xa6);
+ state->afeoverride[off_core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa5 : 0x8f);
+
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7),
+ (0x1 << 2), 0);
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
+ 0xa5), (0x1 << 2), (0x1 << 2));
+
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa7 : 0xa6),
+ (0x1 << 2), (0x1 << 2));
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa5 :
+ 0x8f), (0x1 << 2), (0x1 << 2));
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ state->pwrup[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_PWRUP);
+ state->atten[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN);
+ state->pwrup[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_PWRUP);
+ state->atten[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_ATTEN);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_PWRUP, 0xc);
- if (pi->use_int_tx_iqlo_cal_nphy) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
if ((pi->pubpi.radiorev == 3) ||
(pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
+ (pi->pubpi.radiorev == 6))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN, 0xf0);
+ else if (pi->pubpi.radiorev == 5)
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN,
+ (core == 0) ? 0xf7 : 0xf2);
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN, 0xf0);
- pi->nphy_txcal_pwr_idx[0] =
- txcal_index_2057_rev3n4n6;
- pi->nphy_txcal_pwr_idx[1] =
- txcal_index_2057_rev3n4n6;
- wlc_phy_txpwr_index_nphy(pi, 3,
- txcal_index_2057_rev3n4n6,
- false);
- } else {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_PWRUP, 0x0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_2G_ATTEN, 0xff);
+ } else {
+ state->pwrup[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_PWRUP);
+ state->atten[core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN);
+ state->pwrup[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_PWRUP);
+ state->atten[off_core] =
+ READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_ATTEN);
- pi->nphy_txcal_pwr_idx[0] =
- txcal_index_2057_rev5n7;
- pi->nphy_txcal_pwr_idx[1] =
- txcal_index_2057_rev5n7;
- wlc_phy_txpwr_index_nphy(pi, 3,
- txcal_index_2057_rev5n7,
- false);
- }
- save_bbmult = true;
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_PWRUP, 0xc);
- } else if (NREV_LT(pi->pubpi.phy_rev, 5)) {
- wlc_phy_cal_txgainctrl_nphy(pi, 11, false);
- if (pi->sh->hw_phytxchain != 3) {
- pi->nphy_txcal_pwr_idx[1] =
- pi->nphy_txcal_pwr_idx[0];
- wlc_phy_txpwr_index_nphy(pi, 3,
- pi->
- nphy_txcal_pwr_idx[0],
- true);
- save_bbmult = true;
+ if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN, 0xf4);
+
+ else
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN, 0xf0);
+
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_PWRUP, 0x0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
+ TXRXCOUPLE_5G_ATTEN, 0xff);
+ }
+
+ tone_freq = 4000;
+
+ wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_OFF) << 0);
+
+ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ } else {
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0, 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 1, 0x3, 0);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0x3, 0);
+
+ state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7);
+ state->afeoverride[core] =
+ read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5);
+
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7),
+ (0x1 << 0) | (0x1 << 1) | (0x1 << 2), 0);
+ mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
+ 0xa5),
+ (0x1 << 0) |
+ (0x1 << 1) |
+ (0x1 << 2), (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
+
+ state->vga_master[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER);
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, 0x2b);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ state->fbmix[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_G);
+ state->intpa_master[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_MASTER);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_G,
+ 0x03);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_MASTER, 0x04);
+ } else {
+ state->fbmix[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_A);
+ state->intpa_master[core] =
+ READ_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_MASTER);
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_A,
+ 0x03);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_MASTER, 0x04);
+
+ }
+
+ tone_freq = 4000;
+
+ wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0);
+ }
+}
+
+static void
+wlc_phy_papd_cal_cleanup_nphy(struct brcms_phy *pi,
+ struct nphy_papd_restore_state *state)
+{
+ u8 core;
+
+ wlc_phy_stopplayback_nphy(pi);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_PWRUP, 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_2G_ATTEN,
+ state->atten[core]);
+ } else {
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_PWRUP, 0);
+ WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
+ TXRXCOUPLE_5G_ATTEN,
+ state->atten[core]);
}
+ }
- } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
- if (PHY_IPA(pi)) {
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- wlc_phy_cal_txgainctrl_nphy(pi, 12,
- false);
- } else {
- pi->nphy_txcal_pwr_idx[0] = 80;
- pi->nphy_txcal_pwr_idx[1] = 80;
- wlc_phy_txpwr_index_nphy(pi, 3, 80,
- false);
- save_bbmult = true;
- }
+ if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ 1, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ else
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 2),
+ 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1),
+ 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID2);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, 0x3, 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ write_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7, state->afectrl[core]);
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f :
+ 0xa5, state->afeoverride[core]);
+ }
+
+ wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff,
+ (state->mm & 0xff));
+
+ if (NREV_IS(pi->pubpi.phy_rev, 7)
+ || NREV_GE(pi->pubpi.phy_rev, 8))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi, (0x1 << 7), 0, 0,
+ 1,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ } else {
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 0x3, 1);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 1);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 0, 0x3, 1);
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 0, 0x3, 1);
+
+ for (core = 0; core < pi->pubpi.phy_corenum; core++) {
+
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER,
+ state->vga_master[core]);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_G, state->fbmix[core]);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAG_MASTER,
+ state->intpa_master[core]);
} else {
+ WRITE_RADIO_REG2(pi, RADIO_2056, RX, core,
+ TXFBMIX_A, state->fbmix[core]);
+ WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
+ INTPAA_MASTER,
+ state->intpa_master[core]);
+ }
- wlc_phy_internal_cal_txgain_nphy(pi);
- save_bbmult = true;
+ write_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xa6 : 0xa7, state->afectrl[core]);
+ write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f :
+ 0xa5, state->afeoverride[core]);
+ }
+
+ wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff,
+ (state->mm & 0xff));
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 1);
+ }
+}
+
+static void
+wlc_phy_a1_nphy(struct brcms_phy *pi, u8 core, u32 winsz, u32 start,
+ u32 end)
+{
+ u32 *buf, *src, *dst, sz;
+
+ sz = end - start + 1;
+
+ buf = kmalloc(2 * sizeof(u32) * NPHY_PAPD_EPS_TBL_SIZE, GFP_ATOMIC);
+ if (NULL == buf)
+ return;
+
+ src = buf;
+ dst = buf + NPHY_PAPD_EPS_TBL_SIZE;
+
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ? NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1),
+ NPHY_PAPD_EPS_TBL_SIZE, 0, 32, src);
+
+ do {
+ u32 phy_a1, phy_a2;
+ s32 phy_a3, phy_a4, phy_a5, phy_a6, phy_a7;
+
+ phy_a1 = end - min(end, (winsz >> 1));
+ phy_a2 = min_t(u32, NPHY_PAPD_EPS_TBL_SIZE - 1,
+ end + (winsz >> 1));
+ phy_a3 = phy_a2 - phy_a1 + 1;
+ phy_a6 = 0;
+ phy_a7 = 0;
+
+ do {
+ wlc_phy_papd_decode_epsilon(src[phy_a2], &phy_a4,
+ &phy_a5);
+ phy_a6 += phy_a4;
+ phy_a7 += phy_a5;
+ } while (phy_a2-- != phy_a1);
+
+ phy_a6 /= phy_a3;
+ phy_a7 /= phy_a3;
+ dst[end] = ((u32) phy_a7 << 13) | ((u32) phy_a6 & 0x1fff);
+ } while (end-- != start);
+
+ wlc_phy_table_write_nphy(pi,
+ (core ==
+ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1, sz, start, 32, dst);
+
+ kfree(buf);
+}
+
+static void
+wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains,
+ enum phy_cal_mode cal_mode, u8 core)
+{
+ u16 phy_a1, phy_a2, phy_a3;
+ u16 phy_a4, phy_a5;
+ bool phy_a6;
+ u8 phy_a7, m[2];
+ u32 phy_a8 = 0;
+ struct nphy_txgains phy_a9;
+
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
+ return;
+
+ phy_a7 = (core == PHY_CORE_0) ? 1 : 0;
+
+ phy_a6 = ((cal_mode == CAL_GCTRL)
+ || (cal_mode == CAL_SOFT)) ? true : false;
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+
+ phy_a9 = wlc_phy_get_tx_gain_nphy(pi);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ phy_a5 = ((phy_a9.txlpf[core] << 15) |
+ (phy_a9.txgm[core] << 12) |
+ (phy_a9.pga[core] << 8) |
+ (txgains->gains.pad[core] << 3) |
+ (phy_a9.ipa[core]));
+ else
+ phy_a5 = ((phy_a9.txlpf[core] << 15) |
+ (phy_a9.txgm[core] << 12) |
+ (txgains->gains.pga[core] << 8) |
+ (phy_a9.pad[core] << 3) | (phy_a9.ipa[core]));
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_txgain,
+ phy_a5, (1 << core), 0);
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev <= 4)
+ || (pi->pubpi.radiorev == 6))
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 60 : 79;
+ else
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 45 : 64;
+ } else {
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107;
+ }
+
+ m[phy_a7] = 0;
+ wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]);
+
+ phy_a2 = 63;
+
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6)) {
+ phy_a1 = 30;
+ phy_a3 = 30;
+ } else {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ }
+ } else {
+ if ((pi->pubpi.radiorev == 5)
+ || (pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ } else {
+ phy_a1 = 35;
+ phy_a3 = 35;
}
+ }
- } else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
- if (PHY_IPA(pi)) {
+ if (cal_mode == CAL_GCTRL) {
+ if ((pi->pubpi.radiorev == 5)
+ && (CHSPEC_IS2G(pi->radio_chanspec)))
+ phy_a1 = 55;
+ else if (((pi->pubpi.radiorev == 7) &&
+ (CHSPEC_IS2G(pi->radio_chanspec))) ||
+ ((pi->pubpi.radiorev == 8) &&
+ (CHSPEC_IS2G(pi->radio_chanspec))))
+ phy_a1 = 60;
+ else
+ phy_a1 = 63;
+
+ } else if ((cal_mode != CAL_FULL) && (cal_mode != CAL_SOFT)) {
+
+ phy_a1 = 35;
+ phy_a3 = 35;
+ }
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ write_phy_reg(pi, 0x2a1, 0x80);
+ write_phy_reg(pi, 0x2a2, 0x100);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 4), (11) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 8), (11) << 8);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 0), (0x3) << 0);
+
+ write_phy_reg(pi, 0x2e5, 0x20);
+
+ mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 1, ((core == 0) ? 1 : 2), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, ((core == 0) ? 2 : 1), 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ write_phy_reg(pi, 0x2be, 1);
+ SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000);
+
+ wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
+ 0, 0x3, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID0);
+
+ wlc_phy_table_write_nphy(pi,
+ (core ==
+ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0
+ : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3,
+ 32, &phy_a8);
+
+ if (cal_mode != CAL_GCTRL) {
+ if (CHSPEC_IS5G(pi->radio_chanspec))
+ wlc_phy_a1_nphy(pi, core, 5, 0, 35);
+ }
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_txgain,
+ phy_a5, (1 << core), 1);
+
+ } else {
+
+ if (txgains) {
+ if (txgains->useindex) {
+ phy_a4 = 15 - ((txgains->index) >> 3);
if (CHSPEC_IS2G(pi->radio_chanspec)) {
- wlc_phy_cal_txgainctrl_nphy(pi, 12,
- false);
+ if (NREV_GE(pi->pubpi.phy_rev, 6))
+ phy_a5 = 0x00f7 | (phy_a4 << 8);
+
+ else
+ if (NREV_IS(pi->pubpi.phy_rev, 5))
+ phy_a5 = 0x10f7 | (phy_a4 << 8);
+ else
+ phy_a5 = 0x50f7 | (phy_a4 << 8);
} else {
- wlc_phy_cal_txgainctrl_nphy(pi, 14,
- false);
+ phy_a5 = 0x70f7 | (phy_a4 << 8);
}
+ wlc_phy_rfctrl_override_nphy(pi,
+ (0x1 << 13),
+ phy_a5,
+ (1 << core), 0);
} else {
-
- wlc_phy_internal_cal_txgain_nphy(pi);
- save_bbmult = true;
+ wlc_phy_rfctrl_override_nphy(pi,
+ (0x1 << 13),
+ 0x5bf7,
+ (1 << core), 0);
}
}
- } else {
- wlc_phy_cal_txgainctrl_nphy(pi, 10, false);
- }
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 45 : 64;
+ else
+ m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107;
- if (save_bbmult) {
- wlc_phy_table_read_nphy(pi, 15, 1, 87, 16,
- &pi->nphy_txcal_bbmult);
+ m[phy_a7] = 0;
+ wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]);
+
+ phy_a2 = 63;
+
+ if (cal_mode == CAL_FULL) {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ } else if (cal_mode == CAL_SOFT) {
+ phy_a1 = 25;
+ phy_a3 = 25;
+ } else if (cal_mode == CAL_GCTRL) {
+ phy_a1 = 63;
+ phy_a3 = 25;
+ } else {
+
+ phy_a1 = 25;
+ phy_a3 = 25;
+ }
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (1) << 0);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (0) << 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (1) << 13);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ write_phy_reg(pi, 0x2a1, 0x20);
+ write_phy_reg(pi, 0x2a2, 0x60);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0xf << 4), (9) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0xf << 8), (9) << 8);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0xf << 0), (0x2) << 0);
+
+ write_phy_reg(pi, 0x2e5, 0x20);
+ } else {
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (1) << 11);
+
+ mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (0) << 11);
+
+ write_phy_reg(pi, 0x2a1, 0x80);
+ write_phy_reg(pi, 0x2a2, 0x600);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 4), (0) << 4);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 8), (0) << 8);
+
+ mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x7 << 0), (0x3) << 0);
+
+ mod_phy_reg(pi, 0x2a0, (0x3f << 8), (0x20) << 8);
+
+ }
+
+ mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0);
+
+ mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0x3, 0);
+
+ write_phy_reg(pi, 0x2be, 1);
+ SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000);
+
+ wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0);
+
+ wlc_phy_table_write_nphy(pi,
+ (core ==
+ PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0
+ : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3,
+ 32, &phy_a8);
+
+ if (cal_mode != CAL_GCTRL)
+ wlc_phy_a1_nphy(pi, core, 5, 0, 40);
}
}
-void
-wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, s32 dBm_targetpower,
- bool debug)
+static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core)
{
- int gainctrl_loopidx;
- uint core;
- u16 m0m1, curr_m0m1;
- s32 delta_power;
- s32 txpwrindex;
- s32 qdBm_power[2];
- u16 orig_BBConfig;
- u16 phy_saveregs[4];
- u32 freq_test;
- u16 ampl_test = 250;
- uint stepsize;
- bool phyhang_avoid_state = false;
+ int phy_a1;
+ int phy_a2;
+ bool phy_a3;
+ struct nphy_ipa_txcalgains phy_a4;
+ bool phy_a5 = false;
+ bool phy_a6 = true;
+ s32 phy_a7, phy_a8;
+ u32 phy_a9;
+ int phy_a10;
+ bool phy_a11 = false;
+ int phy_a12;
+ u8 phy_a13 = 0;
+ u8 phy_a14;
+ u8 *phy_a15 = NULL;
+
+ phy_a4.useindex = true;
+ phy_a12 = start_gain;
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- stepsize = 2;
- } else {
+ phy_a2 = 20;
+ phy_a1 = 1;
- stepsize = 1;
- }
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev == 5) {
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- freq_test = 5000;
- } else {
- freq_test = 2500;
- }
+ phy_a15 = pad_gain_codes_used_2057rev5;
+ phy_a13 =
+ sizeof(pad_gain_codes_used_2057rev5) /
+ sizeof(pad_gain_codes_used_2057rev5
+ [0]) - 1;
- wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true);
- wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true);
+ } else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
+ phy_a15 = pad_gain_codes_used_2057rev7;
+ phy_a13 =
+ sizeof(pad_gain_codes_used_2057rev7) /
+ sizeof(pad_gain_codes_used_2057rev7
+ [0]) - 1;
- phyhang_avoid_state = pi->phyhang_avoid;
- pi->phyhang_avoid = false;
+ } else {
- phy_saveregs[0] = read_phy_reg(pi, 0x91);
- phy_saveregs[1] = read_phy_reg(pi, 0x92);
- phy_saveregs[2] = read_phy_reg(pi, 0xe7);
- phy_saveregs[3] = read_phy_reg(pi, 0xec);
- wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 1,
- RADIO_MIMO_CORESEL_CORE1 |
- RADIO_MIMO_CORESEL_CORE2);
+ phy_a15 = pad_all_gain_codes_2057;
+ phy_a13 = sizeof(pad_all_gain_codes_2057) /
+ sizeof(pad_all_gain_codes_2057[0]) -
+ 1;
+ }
- if (!debug) {
- wlc_phy_rfctrlintc_override_nphy(pi,
- NPHY_RfctrlIntc_override_TRSW,
- 0x2, RADIO_MIMO_CORESEL_CORE1);
- wlc_phy_rfctrlintc_override_nphy(pi,
- NPHY_RfctrlIntc_override_TRSW,
- 0x8, RADIO_MIMO_CORESEL_CORE2);
- } else {
- wlc_phy_rfctrlintc_override_nphy(pi,
- NPHY_RfctrlIntc_override_TRSW,
- 0x1, RADIO_MIMO_CORESEL_CORE1);
- wlc_phy_rfctrlintc_override_nphy(pi,
- NPHY_RfctrlIntc_override_TRSW,
- 0x7, RADIO_MIMO_CORESEL_CORE2);
- }
+ } else {
- orig_BBConfig = read_phy_reg(pi, 0x01);
- mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+ phy_a15 = pga_all_gain_codes_2057;
+ phy_a13 = sizeof(pga_all_gain_codes_2057) /
+ sizeof(pga_all_gain_codes_2057[0]) - 1;
+ }
- wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1);
+ phy_a14 = 0;
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- txpwrindex = (s32) pi->nphy_cal_orig_pwr_idx[core];
+ for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) {
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ phy_a4.gains.pad[core] =
+ (u16) phy_a15[phy_a12];
+ else
+ phy_a4.gains.pga[core] =
+ (u16) phy_a15[phy_a12];
- for (gainctrl_loopidx = 0; gainctrl_loopidx < 2;
- gainctrl_loopidx++) {
- wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0,
- false);
+ wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core);
- if (core == PHY_CORE_0) {
- curr_m0m1 = m0m1 & 0xff00;
- } else {
- curr_m0m1 = m0m1 & 0x00ff;
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ?
+ NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1), 1,
+ 63, 32, &phy_a9);
+
+ wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8);
+
+ phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) ||
+ (phy_a8 == 4095) || (phy_a8 == -4096));
+
+ if (!phy_a6 && (phy_a3 != phy_a5)) {
+ if (!phy_a3)
+ phy_a12 -= (u8) phy_a1;
+
+ phy_a11 = true;
+ break;
}
- wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &curr_m0m1);
- wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &curr_m0m1);
+ if (phy_a3)
+ phy_a12 += (u8) phy_a1;
+ else
+ phy_a12 -= (u8) phy_a1;
- udelay(50);
+ if ((phy_a12 < phy_a14) || (phy_a12 > phy_a13)) {
+ if (phy_a12 < phy_a14)
+ phy_a12 = phy_a14;
+ else
+ phy_a12 = phy_a13;
- wlc_phy_est_tonepwr_nphy(pi, qdBm_power,
- NPHY_CAL_TSSISAMPS);
+ phy_a11 = true;
+ break;
+ }
- pi->nphy_bb_mult_save = 0;
- wlc_phy_stopplayback_nphy(pi);
+ phy_a6 = false;
+ phy_a5 = phy_a3;
+ }
- delta_power = (dBm_targetpower * 4) - qdBm_power[core];
+ } else {
+ phy_a2 = 10;
+ phy_a1 = 8;
+ for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) {
+ phy_a4.index = (u8) phy_a12;
+ wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core);
- txpwrindex -= stepsize * delta_power;
- if (txpwrindex < 0) {
- txpwrindex = 0;
- } else if (txpwrindex > 127) {
- txpwrindex = 127;
+ wlc_phy_table_read_nphy(pi,
+ (core ==
+ PHY_CORE_0 ?
+ NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1), 1,
+ 63, 32, &phy_a9);
+
+ wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8);
+
+ phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) ||
+ (phy_a8 == 4095) || (phy_a8 == -4096));
+
+ if (!phy_a6 && (phy_a3 != phy_a5)) {
+ if (!phy_a3)
+ phy_a12 -= (u8) phy_a1;
+
+ phy_a11 = true;
+ break;
}
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- if (NREV_IS(pi->pubpi.phy_rev, 4) &&
- (pi->srom_fem5g.extpagain == 3)) {
- if (txpwrindex < 30) {
- txpwrindex = 30;
- }
- }
- } else {
- if (NREV_GE(pi->pubpi.phy_rev, 5) &&
- (pi->srom_fem2g.extpagain == 3)) {
- if (txpwrindex < 50) {
- txpwrindex = 50;
- }
- }
+ if (phy_a3)
+ phy_a12 += (u8) phy_a1;
+ else
+ phy_a12 -= (u8) phy_a1;
+
+ if ((phy_a12 < 0) || (phy_a12 > 127)) {
+ if (phy_a12 < 0)
+ phy_a12 = 0;
+ else
+ phy_a12 = 127;
+
+ phy_a11 = true;
+ break;
}
- wlc_phy_txpwr_index_nphy(pi, (1 << core),
- (u8) txpwrindex, true);
+ phy_a6 = false;
+ phy_a5 = phy_a3;
}
- pi->nphy_txcal_pwr_idx[core] = (u8) txpwrindex;
+ }
- if (debug) {
- u16 radio_gain;
- u16 dbg_m0m1;
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ return (u8) phy_a15[phy_a12];
+ else
+ return (u8) phy_a12;
- wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &dbg_m0m1);
+}
- wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0,
- false);
+static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal)
+{
+ struct nphy_ipa_txcalgains phy_b1[2];
+ struct nphy_papd_restore_state phy_b2;
+ bool phy_b3;
+ u8 phy_b4;
+ u8 phy_b5;
+ s16 phy_b6, phy_b7, phy_b8;
+ u16 phy_b9;
+ s16 phy_b10, phy_b11, phy_b12;
- wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &dbg_m0m1);
- wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &dbg_m0m1);
+ phy_b11 = 0;
+ phy_b12 = 0;
+ phy_b7 = 0;
+ phy_b8 = 0;
+ phy_b6 = 0;
- udelay(100);
+ if (pi->nphy_papd_skip == 1)
+ return;
- wlc_phy_est_tonepwr_nphy(pi, qdBm_power,
- NPHY_CAL_TSSISAMPS);
+ phy_b3 = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
+ if (!phy_b3)
+ wlapi_suspend_mac_and_wait(pi->sh->physhim);
- wlc_phy_table_read_nphy(pi, 7, 1, (0x110 + core), 16,
- &radio_gain);
+ wlc_phy_stay_in_carriersearch_nphy(pi, true);
- mdelay(4000);
- pi->nphy_bb_mult_save = 0;
- wlc_phy_stopplayback_nphy(pi);
+ pi->nphy_force_papd_cal = false;
+
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++)
+ pi->nphy_papd_tx_gain_at_last_cal[phy_b5] =
+ wlc_phy_txpwr_idx_cur_get_nphy(pi, phy_b5);
+
+ pi->nphy_papd_last_cal = pi->sh->now;
+ pi->nphy_papd_recal_counter++;
+
+ phy_b4 = pi->nphy_txpwrctrl;
+ wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
+
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL0, 64, 0, 32,
+ nphy_papd_scaltbl);
+ wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL1, 64, 0, 32,
+ nphy_papd_scaltbl);
+
+ phy_b9 = read_phy_reg(pi, 0x01);
+ mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
+
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
+ s32 i, val = 0;
+ for (i = 0; i < 64; i++)
+ wlc_phy_table_write_nphy(pi,
+ ((phy_b5 ==
+ PHY_CORE_0) ?
+ NPHY_TBL_ID_EPSILONTBL0 :
+ NPHY_TBL_ID_EPSILONTBL1), 1,
+ i, 32, &val);
+ }
+
+ wlc_phy_ipa_restore_tx_digi_filts_nphy(pi);
+
+ phy_b2.mm = wlc_phy_ipa_get_bbmult_nphy(pi);
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
+ wlc_phy_papd_cal_setup_nphy(pi, &phy_b2, phy_b5);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if ((pi->pubpi.radiorev == 3)
+ || (pi->pubpi.radiorev == 4)
+ || (pi->pubpi.radiorev == 6)) {
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 23;
+ } else if (pi->pubpi.radiorev == 5) {
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 0;
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ wlc_phy_a3_nphy(
+ pi,
+ pi->
+ nphy_papd_cal_gain_index
+ [phy_b5],
+ phy_b5);
+
+ } else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8)) {
+
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 0;
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ wlc_phy_a3_nphy(
+ pi,
+ pi->
+ nphy_papd_cal_gain_index
+ [phy_b5],
+ phy_b5);
+
+ }
+
+ phy_b1[phy_b5].gains.pad[phy_b5] =
+ pi->nphy_papd_cal_gain_index[phy_b5];
+
+ } else {
+ pi->nphy_papd_cal_gain_index[phy_b5] = 0;
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ wlc_phy_a3_nphy(
+ pi,
+ pi->
+ nphy_papd_cal_gain_index
+ [phy_b5], phy_b5);
+ phy_b1[phy_b5].gains.pga[phy_b5] =
+ pi->nphy_papd_cal_gain_index[phy_b5];
+ }
+ } else {
+ phy_b1[phy_b5].useindex = true;
+ phy_b1[phy_b5].index = 16;
+ phy_b1[phy_b5].index =
+ wlc_phy_a3_nphy(pi, phy_b1[phy_b5].index,
+ phy_b5);
+
+ pi->nphy_papd_cal_gain_index[phy_b5] =
+ 15 - ((phy_b1[phy_b5].index) >> 3);
}
+
+ switch (pi->nphy_papd_cal_type) {
+ case 0:
+ wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_FULL, phy_b5);
+ break;
+ case 1:
+ wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_SOFT, phy_b5);
+ break;
+ }
+
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2);
}
- wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_txcal_pwr_idx[0], true);
- wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_txcal_pwr_idx[1], true);
+ if (NREV_LT(pi->pubpi.phy_rev, 7))
+ wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2);
- wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &pi->nphy_txcal_bbmult);
+ for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
+ int eps_offset = 0;
- write_phy_reg(pi, 0x01, orig_BBConfig);
+ if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ if (pi->pubpi.radiorev == 3)
+ eps_offset = -2;
+ else if (pi->pubpi.radiorev == 5)
+ eps_offset = 3;
+ else
+ eps_offset = -1;
+ } else {
+ eps_offset = 2;
+ }
- write_phy_reg(pi, 0x91, phy_saveregs[0]);
- write_phy_reg(pi, 0x92, phy_saveregs[1]);
- write_phy_reg(pi, 0xe7, phy_saveregs[2]);
- write_phy_reg(pi, 0xec, phy_saveregs[3]);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ phy_b8 = phy_b1[phy_b5].gains.pad[phy_b5];
+ phy_b10 = 0;
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6)) {
+ phy_b12 = -(
+ nphy_papd_padgain_dlt_2g_2057rev3n4
+ [phy_b8] + 1) / 2;
+ phy_b10 = -1;
+ } else if (pi->pubpi.radiorev == 5) {
+ phy_b12 = -(
+ nphy_papd_padgain_dlt_2g_2057rev5
+ [phy_b8] + 1) / 2;
+ } else if ((pi->pubpi.radiorev == 7) ||
+ (pi->pubpi.radiorev == 8)) {
+ phy_b12 = -(
+ nphy_papd_padgain_dlt_2g_2057rev7
+ [phy_b8] + 1) / 2;
+ }
+ } else {
+ phy_b7 = phy_b1[phy_b5].gains.pga[phy_b5];
+ if ((pi->pubpi.radiorev == 3) ||
+ (pi->pubpi.radiorev == 4) ||
+ (pi->pubpi.radiorev == 6))
+ phy_b11 =
+ -(nphy_papd_pgagain_dlt_5g_2057
+ [phy_b7]
+ + 1) / 2;
+ else if ((pi->pubpi.radiorev == 7)
+ || (pi->pubpi.radiorev == 8))
+ phy_b11 = -(
+ nphy_papd_pgagain_dlt_5g_2057rev7
+ [phy_b7] + 1) / 2;
- pi->phyhang_avoid = phyhang_avoid_state;
+ phy_b10 = -9;
+ }
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-}
+ if (CHSPEC_IS2G(pi->radio_chanspec))
+ phy_b6 =
+ -60 + 27 + eps_offset + phy_b12 +
+ phy_b10;
+ else
+ phy_b6 =
+ -60 + 27 + eps_offset + phy_b11 +
+ phy_b10;
-static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core)
-{
- int index;
- u32 bbmult_scale;
- u16 bbmult;
- u16 tblentry;
+ mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 :
+ 0x29c, (0x1ff << 7), (phy_b6) << 7);
- struct nphy_txiqcal_ladder ladder_lo[] = {
- {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
- {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5},
- {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7}
- };
+ pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6;
+ } else {
+ if (NREV_LT(pi->pubpi.phy_rev, 5))
+ eps_offset = 4;
+ else
+ eps_offset = 2;
- struct nphy_txiqcal_ladder ladder_iq[] = {
- {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0},
- {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1},
- {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7}
- };
+ phy_b7 = 15 - ((phy_b1[phy_b5].index) >> 3);
- bbmult = (core == PHY_CORE_0) ?
- ((pi->nphy_txcal_bbmult >> 8) & 0xff) : (pi->
- nphy_txcal_bbmult & 0xff);
+ if (CHSPEC_IS2G(pi->radio_chanspec)) {
+ phy_b11 =
+ -(nphy_papd_pga_gain_delta_ipa_2g[
+ phy_b7] +
+ 1) / 2;
+ phy_b10 = 0;
+ } else {
+ phy_b11 =
+ -(nphy_papd_pga_gain_delta_ipa_5g[
+ phy_b7] +
+ 1) / 2;
+ phy_b10 = -9;
+ }
- for (index = 0; index < 18; index++) {
- bbmult_scale = ladder_lo[index].percent * bbmult;
- bbmult_scale /= 100;
+ phy_b6 = -60 + 27 + eps_offset + phy_b11 + phy_b10;
- tblentry =
- ((bbmult_scale & 0xff) << 8) | ladder_lo[index].g_env;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index, 16,
- &tblentry);
+ mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 :
+ 0x29c, (0x1ff << 7), (phy_b6) << 7);
- bbmult_scale = ladder_iq[index].percent * bbmult;
- bbmult_scale /= 100;
+ pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6;
+ }
+ }
+
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 :
+ 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
+
+ if (NREV_GE(pi->pubpi.phy_rev, 6)) {
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 13), (0) << 13);
+
+ } else {
+ mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (0) << 11);
+
+ mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 :
+ 0x2a4, (0x1 << 11), (0) << 11);
- tblentry =
- ((bbmult_scale & 0xff) << 8) | ladder_iq[index].g_env;
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index + 32,
- 16, &tblentry);
}
+ pi->nphy_papdcomp = NPHY_PAPD_COMP_ON;
+
+ write_phy_reg(pi, 0x01, phy_b9);
+
+ wlc_phy_ipa_set_tx_digi_filts_nphy(pi);
+
+ wlc_phy_txpwrctrl_enable_nphy(pi, phy_b4);
+ if (phy_b4 == PHY_TPC_HW_OFF) {
+ wlc_phy_txpwr_index_nphy(pi, (1 << 0),
+ (s8) (pi->nphy_txpwrindex[0].
+ index_internal), false);
+ wlc_phy_txpwr_index_nphy(pi, (1 << 1),
+ (s8) (pi->nphy_txpwrindex[1].
+ index_internal), false);
+ }
+
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
+
+ if (!phy_b3)
+ wlapi_enable_mac(pi->sh->physhim);
}
void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
@@ -23738,11 +25671,6 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
bool restore_tx_gain = false;
bool mphase;
- if (NORADIO_ENAB(pi->pubpi)) {
- wlc_phy_cal_perical_mphase_reset(pi);
- return;
- }
-
if (PHY_MUTED(pi))
return;
@@ -23751,19 +25679,18 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
else if (caltype == PHY_PERICAL_PARTIAL)
fullcal = false;
- if (pi->cal_type_override != PHY_PERICAL_AUTO) {
+ if (pi->cal_type_override != PHY_PERICAL_AUTO)
fullcal =
- (pi->cal_type_override == PHY_PERICAL_FULL) ? true : false;
- }
+ (pi->cal_type_override ==
+ PHY_PERICAL_FULL) ? true : false;
if ((pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT)) {
if (pi->nphy_txiqlocal_chanspec != pi->radio_chanspec)
wlc_phy_cal_perical_mphase_restart(pi);
}
- if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL)) {
+ if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL))
wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000);
- }
wlapi_suspend_mac_and_wait(pi->sh->physhim);
@@ -23772,9 +25699,9 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_IDLE) ||
(pi->mphase_cal_phase_id == MPHASE_CAL_STATE_INIT)) {
pi->nphy_cal_orig_pwr_idx[0] =
- (u8) ((read_phy_reg(pi, 0x1ed) >> 8) & 0x7f);
+ (u8) ((read_phy_reg(pi, 0x1ed) >> 8) & 0x7f);
pi->nphy_cal_orig_pwr_idx[1] =
- (u8) ((read_phy_reg(pi, 0x1ee) >> 8) & 0x7f);
+ (u8) ((read_phy_reg(pi, 0x1ee) >> 8) & 0x7f);
if (pi->nphy_txpwrctrl != PHY_TPC_HW_OFF) {
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2,
@@ -23803,7 +25730,8 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
target_gain = pi->nphy_cal_target_gain;
}
if (0 ==
- wlc_phy_cal_txiqlo_nphy(pi, target_gain, fullcal, mphase)) {
+ wlc_phy_cal_txiqlo_nphy(pi, target_gain, fullcal,
+ mphase)) {
if (PHY_IPA(pi))
wlc_phy_a4(pi, true);
@@ -23815,13 +25743,9 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
wlc_phyreg_enter((struct brcms_phy_pub *) pi);
if (0 == wlc_phy_cal_rxiq_nphy(pi, target_gain,
- (pi->
- first_cal_after_assoc
- || (pi->
- cal_type_override
- ==
- PHY_PERICAL_FULL))
- ? 2 : 0, false)) {
+ (pi->first_cal_after_assoc ||
+ (pi->cal_type_override ==
+ PHY_PERICAL_FULL)) ? 2 : 0, false)) {
wlc_phy_savecal_nphy(pi);
wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
@@ -23829,9 +25753,8 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
pi->nphy_perical_last = pi->sh->now;
}
}
- if (caltype != PHY_PERICAL_AUTO) {
+ if (caltype != PHY_PERICAL_AUTO)
wlc_phy_rssi_cal_nphy(pi);
- }
if (pi->first_cal_after_assoc
|| (pi->cal_type_override == PHY_PERICAL_FULL)) {
@@ -23840,18 +25763,17 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
wlc_phy_txpwrctrl_pwr_setup_nphy(pi);
}
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
wlc_phy_radio205x_vcocal_nphy(pi);
- }
} else {
switch (pi->mphase_cal_phase_id) {
case MPHASE_CAL_STATE_INIT:
pi->nphy_perical_last = pi->sh->now;
pi->nphy_txiqlocal_chanspec = pi->radio_chanspec;
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
wlc_phy_precal_txgain_nphy(pi);
- }
+
pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi);
pi->mphase_cal_phase_id++;
break;
@@ -23866,8 +25788,8 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
pi->nphy_rxcal_active = true;
if (wlc_phy_cal_txiqlo_nphy
- (pi, pi->nphy_cal_target_gain, fullcal,
- true) != 0) {
+ (pi, pi->nphy_cal_target_gain, fullcal,
+ true) != 0) {
wlc_phy_cal_perical_mphase_reset(pi);
break;
@@ -23875,20 +25797,19 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
if (NREV_LE(pi->pubpi.phy_rev, 2) &&
(pi->mphase_cal_phase_id ==
- MPHASE_CAL_STATE_TXPHASE4)) {
+ MPHASE_CAL_STATE_TXPHASE4))
pi->mphase_cal_phase_id += 2;
- } else {
+ else
pi->mphase_cal_phase_id++;
- }
break;
case MPHASE_CAL_STATE_PAPDCAL:
if ((pi->radar_percal_mask & 0x2) != 0)
pi->nphy_rxcal_active = true;
- if (PHY_IPA(pi)) {
+ if (PHY_IPA(pi))
wlc_phy_a4(pi, true);
- }
+
pi->mphase_cal_phase_id++;
break;
@@ -23899,9 +25820,8 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
(pi->first_cal_after_assoc ||
(pi->cal_type_override ==
PHY_PERICAL_FULL)) ? 2 : 0,
- false) == 0) {
+ false) == 0)
wlc_phy_savecal_nphy(pi);
- }
pi->mphase_cal_phase_id++;
break;
@@ -23912,16 +25832,15 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
wlc_phy_txpwrctrl_coeff_setup_nphy(pi);
wlc_phy_rssi_cal_nphy(pi);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
wlc_phy_radio205x_vcocal_nphy(pi);
- }
+
restore_tx_gain = true;
- if (pi->first_cal_after_assoc) {
+ if (pi->first_cal_after_assoc)
pi->mphase_cal_phase_id++;
- } else {
+ else
wlc_phy_cal_perical_mphase_reset(pi);
- }
break;
@@ -23962,15 +25881,15 @@ void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype)
} else {
wlc_phy_txpwr_index_nphy(pi, (1 << 0),
(s8) (pi->
- nphy_txpwrindex
- [0].
- index_internal),
+ nphy_txpwrindex
+ [0].
+ index_internal),
false);
wlc_phy_txpwr_index_nphy(pi, (1 << 1),
(s8) (pi->
- nphy_txpwrindex
- [1].
- index_internal),
+ nphy_txpwrindex
+ [1].
+ index_internal),
false);
}
}
@@ -24007,35 +25926,35 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
u16 tbl_tx_iqlo_cal_loft_ladder_20[] = {
0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901,
- 0x1902,
+ 0x1902,
0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607,
- 0x6407
+ 0x6407
};
u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = {
0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400,
- 0x3200,
+ 0x3200,
0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406,
- 0x6407
+ 0x6407
};
u16 tbl_tx_iqlo_cal_loft_ladder_40[] = {
0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201,
- 0x1202,
+ 0x1202,
0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207,
- 0x4707
+ 0x4707
};
u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = {
0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900,
- 0x2300,
+ 0x2300,
0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706,
- 0x4707
+ 0x4707
};
u16 tbl_tx_iqlo_cal_startcoefs[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000
+ 0x0000
};
u16 tbl_tx_iqlo_cal_cmds_fullcal[] = {
@@ -24071,11 +25990,10 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
pi->phyhang_avoid = false;
}
- if (CHSPEC_IS40(pi->radio_chanspec)) {
+ if (CHSPEC_IS40(pi->radio_chanspec))
phy_bw = 40;
- } else {
+ else
phy_bw = 20;
- }
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save);
@@ -24117,11 +26035,10 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
16, tbl_ptr);
}
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
write_phy_reg(pi, 0xc2, 0x8ad9);
- } else {
+ else
write_phy_reg(pi, 0xc2, 0x8aa9);
- }
max_val = 250;
tone_freq = (phy_bw == 20) ? 2500 : 5000;
@@ -24131,7 +26048,8 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
bcmerror = 0;
} else {
bcmerror =
- wlc_phy_tx_tone_nphy(pi, tone_freq, max_val, 1, 0, false);
+ wlc_phy_tx_tone_nphy(pi, tone_freq, max_val, 1, 0,
+ false);
}
if (bcmerror == 0) {
@@ -24139,19 +26057,15 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) {
tbl_ptr = pi->mphase_txcal_bestcoeffs;
tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs);
- if (NREV_LT(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
tbl_len -= 2;
- }
} else {
if ((!fullcal) && (pi->nphy_txiqlocal_coeffsvalid)) {
tbl_ptr = pi->nphy_txiqlocal_bestc;
tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc);
- if (NREV_LT(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
tbl_len -= 2;
- }
} else {
fullcal = true;
@@ -24159,14 +26073,12 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
if (NREV_GE(pi->pubpi.phy_rev, 3)) {
tbl_ptr =
tbl_tx_iqlo_cal_startcoefs_nphyrev3;
- tbl_len =
- ARRAY_SIZE
- (tbl_tx_iqlo_cal_startcoefs_nphyrev3);
+ tbl_len = ARRAY_SIZE(
+ tbl_tx_iqlo_cal_startcoefs_nphyrev3);
} else {
tbl_ptr = tbl_tx_iqlo_cal_startcoefs;
- tbl_len =
- ARRAY_SIZE
- (tbl_tx_iqlo_cal_startcoefs);
+ tbl_len = ARRAY_SIZE(
+ tbl_tx_iqlo_cal_startcoefs);
}
}
}
@@ -24175,21 +26087,22 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
if (fullcal) {
max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
- ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3) :
- ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_fullcal);
+ ARRAY_SIZE(
+ tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3) :
+ ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_fullcal);
} else {
max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
- ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_recal_nphyrev3) :
- ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_recal);
+ ARRAY_SIZE(
+ tbl_tx_iqlo_cal_cmds_recal_nphyrev3) :
+ ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_recal);
}
if (mphase) {
cal_cnt = pi->mphase_txcal_cmdidx;
- if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds) {
+ if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds)
num_cals = cal_cnt + pi->mphase_txcal_numcmds;
- } else {
+ else
num_cals = max_cal_cmds;
- }
} else {
cal_cnt = 0;
num_cals = max_cal_cmds;
@@ -24199,13 +26112,14 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
if (fullcal) {
cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
- tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3
- [cal_cnt] :
- tbl_tx_iqlo_cal_cmds_fullcal[cal_cnt];
+ tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3
+ [cal_cnt] :
+ tbl_tx_iqlo_cal_cmds_fullcal[cal_cnt];
} else {
cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ?
- tbl_tx_iqlo_cal_cmds_recal_nphyrev3[cal_cnt]
- : tbl_tx_iqlo_cal_cmds_recal[cal_cnt];
+ tbl_tx_iqlo_cal_cmds_recal_nphyrev3[
+ cal_cnt]
+ : tbl_tx_iqlo_cal_cmds_recal[cal_cnt];
}
core_no = ((cal_cmd & 0x3000) >> 12);
@@ -24216,15 +26130,16 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
PHY_IPA(pi)
&& (CHSPEC_IS2G(pi->radio_chanspec)))) {
if (!ladder_updated[core_no]) {
- wlc_phy_update_txcal_ladder_nphy(pi,
- core_no);
+ wlc_phy_update_txcal_ladder_nphy(
+ pi,
+ core_no);
ladder_updated[core_no] = true;
}
}
val =
- (cal_params[core_no].
- ncorr[cal_type] << 8) | NPHY_N_GCTL;
+ (cal_params[core_no].
+ ncorr[cal_type] << 8) | NPHY_N_GCTL;
write_phy_reg(pi, 0xc1, val);
if ((cal_type == 1) || (cal_type == 3)
@@ -24272,8 +26187,8 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
}
mphase_cal_lastphase =
- (NREV_LE(pi->pubpi.phy_rev, 2)) ?
- MPHASE_CAL_STATE_TXPHASE4 : MPHASE_CAL_STATE_TXPHASE5;
+ (NREV_LE(pi->pubpi.phy_rev, 2)) ?
+ MPHASE_CAL_STATE_TXPHASE4 : MPHASE_CAL_STATE_TXPHASE5;
if (!mphase
|| (pi->mphase_cal_phase_id == mphase_cal_lastphase)) {
@@ -24303,10 +26218,9 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
16, tbl_buf);
tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc);
- if (NREV_LT(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
tbl_len -= 2;
- }
+
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
tbl_len, 96, 16,
pi->nphy_txiqlocal_bestc);
@@ -24315,10 +26229,9 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
pi->nphy_txiqlocal_chanspec = pi->radio_chanspec;
} else {
tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs);
- if (NREV_LT(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_LT(pi->pubpi.phy_rev, 3))
tbl_len -= 2;
- }
+
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL,
tbl_len, 96, 16,
pi->mphase_txcal_bestcoeffs);
@@ -24343,9 +26256,8 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
wlc_phy_tx_iq_war_nphy(pi);
}
- if (NREV_GE(pi->pubpi.phy_rev, 4)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 4))
pi->phyhang_avoid = phyhang_avoid_state;
- }
wlc_phy_stay_in_carriersearch_nphy(pi, false);
@@ -24387,18 +26299,6 @@ static void wlc_phy_reapply_txcal_coeffs_nphy(struct brcms_phy *pi)
}
}
-static void wlc_phy_tx_iq_war_nphy(struct brcms_phy *pi)
-{
- struct nphy_iq_comp tx_comp;
-
- wlc_phy_table_read_nphy(pi, 15, 4, 0x50, 16, (void *)&tx_comp);
-
- wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ, tx_comp.a0);
- wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 2, tx_comp.b0);
- wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 4, tx_comp.a1);
- wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 6, tx_comp.b1);
-}
-
void
wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write,
struct nphy_iq_comp *pcomp)
@@ -24438,14 +26338,17 @@ wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est,
if ((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) == 0) {
for (core = 0; core < pi->pubpi.phy_corenum; core++) {
est[core].i_pwr =
- (read_phy_reg(pi, NPHY_IqestipwrAccHi(core)) << 16)
- | read_phy_reg(pi, NPHY_IqestipwrAccLo(core));
+ (read_phy_reg(pi,
+ NPHY_IqestipwrAccHi(core)) << 16)
+ | read_phy_reg(pi, NPHY_IqestipwrAccLo(core));
est[core].q_pwr =
- (read_phy_reg(pi, NPHY_IqestqpwrAccHi(core)) << 16)
- | read_phy_reg(pi, NPHY_IqestqpwrAccLo(core));
+ (read_phy_reg(pi,
+ NPHY_IqestqpwrAccHi(core)) << 16)
+ | read_phy_reg(pi, NPHY_IqestqpwrAccLo(core));
est[core].iq_prod =
- (read_phy_reg(pi, NPHY_IqestIqAccHi(core)) << 16) |
- read_phy_reg(pi, NPHY_IqestIqAccLo(core));
+ (read_phy_reg(pi,
+ NPHY_IqestIqAccHi(core)) << 16) |
+ read_phy_reg(pi, NPHY_IqestIqAccLo(core));
}
}
}
@@ -24470,7 +26373,7 @@ static void wlc_phy_calc_rx_iq_comp_nphy(struct brcms_phy *pi, u8 core_mask)
new_comp.a0 = new_comp.b0 = new_comp.a1 = new_comp.b1 = 0x0;
wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp);
- cal_try:
+cal_try:
wlc_phy_rx_iq_est_nphy(pi, est, 0x4000, 32, 0);
new_comp = old_comp;
@@ -24561,7 +26464,7 @@ static void wlc_phy_calc_rx_iq_comp_nphy(struct brcms_phy *pi, u8 core_mask)
if (bcmerror != 0) {
printk(KERN_DEBUG "%s: Failed, cnt = %d\n", __func__,
- cal_retry);
+ cal_retry);
if (cal_retry < CAL_RETRY_CNT) {
cal_retry++;
@@ -24584,121 +26487,125 @@ static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core)
if (rx_core == PHY_CORE_0) {
if (CHSPEC_IS5G(pi->radio_chanspec)) {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP);
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN);
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN);
write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP,
- 0x3);
+ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP,
+ 0x3);
write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN,
- 0xaf);
+ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN,
+ 0xaf);
} else {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP);
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN);
-
- write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP,
- 0x3);
- write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN,
- 0x7f);
+ read_radio_reg(pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN);
+
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP,
+ 0x3);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN,
+ 0x7f);
}
} else {
if (CHSPEC_IS5G(pi->radio_chanspec)) {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP);
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN);
-
- write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP,
- 0x3);
- write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN,
- 0xaf);
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN);
+
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP,
+ 0x3);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN,
+ 0xaf);
} else {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP);
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN);
+ read_radio_reg(pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN);
write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP,
- 0x3);
+ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP,
+ 0x3);
write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN,
- 0x7f);
+ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN,
+ 0x7f);
}
}
} else {
if (rx_core == PHY_CORE_0) {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi,
- RADIO_2056_TX_RXIQCAL_TXMUX |
- RADIO_2056_TX1);
+ read_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX1);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi,
- RADIO_2056_RX_RXIQCAL_RXMUX |
- RADIO_2056_RX0);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX0);
if (pi->pubpi.radiorev >= 5) {
pi->tx_rx_cal_radio_saveregs[2] =
- read_radio_reg(pi,
- RADIO_2056_RX_RXSPARE2 |
- RADIO_2056_RX0);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX0);
pi->tx_rx_cal_radio_saveregs[3] =
- read_radio_reg(pi,
- RADIO_2056_TX_TXSPARE2 |
- RADIO_2056_TX1);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX1);
}
if (CHSPEC_IS5G(pi->radio_chanspec)) {
if (pi->pubpi.radiorev >= 5) {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAA_MASTER
- | RADIO_2056_RX0);
+ read_radio_reg(pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX0);
- write_radio_reg(pi,
- RADIO_2056_RX_LNAA_MASTER
- | RADIO_2056_RX0, 0x40);
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX0, 0x40);
write_radio_reg(pi,
- RADIO_2056_TX_TXSPARE2 |
- RADIO_2056_TX1, bias_a);
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX1, bias_a);
write_radio_reg(pi,
- RADIO_2056_RX_RXSPARE2 |
- RADIO_2056_RX0, bias_a);
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX0, bias_a);
} else {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAA_TUNE
- | RADIO_2056_RX0);
+ read_radio_reg(pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX0);
offtune_val =
- (pi->
- tx_rx_cal_radio_saveregs[2] & 0xF0)
- >> 8;
+ (pi->tx_rx_cal_radio_saveregs
+ [2] & 0xF0) >> 8;
offtune_val =
- (offtune_val <= 0x7) ? 0xF : 0;
+ (offtune_val <= 0x7) ? 0xF : 0;
mod_radio_reg(pi,
RADIO_2056_RX_LNAA_TUNE |
@@ -24715,34 +26622,41 @@ static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core)
} else {
if (pi->pubpi.radiorev >= 5) {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAG_MASTER
- | RADIO_2056_RX0);
-
- write_radio_reg(pi,
- RADIO_2056_RX_LNAG_MASTER
- | RADIO_2056_RX0, 0x40);
-
- write_radio_reg(pi,
- RADIO_2056_TX_TXSPARE2 |
- RADIO_2056_TX1, bias_g);
-
- write_radio_reg(pi,
- RADIO_2056_RX_RXSPARE2 |
- RADIO_2056_RX0, bias_g);
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX0);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX0, 0x40);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TXSPARE2
+ |
+ RADIO_2056_TX1, bias_g);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_RXSPARE2
+ |
+ RADIO_2056_RX0, bias_g);
} else {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAG_TUNE
- | RADIO_2056_RX0);
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX0);
offtune_val =
- (pi->
- tx_rx_cal_radio_saveregs[2] & 0xF0)
- >> 8;
+ (pi->
+ tx_rx_cal_radio_saveregs[2] &
+ 0xF0) >> 8;
offtune_val =
- (offtune_val <= 0x7) ? 0xF : 0;
+ (offtune_val <= 0x7) ? 0xF : 0;
mod_radio_reg(pi,
RADIO_2056_RX_LNAG_TUNE |
@@ -24760,56 +26674,63 @@ static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core)
} else {
pi->tx_rx_cal_radio_saveregs[0] =
- read_radio_reg(pi,
- RADIO_2056_TX_RXIQCAL_TXMUX |
- RADIO_2056_TX0);
+ read_radio_reg(pi,
+ RADIO_2056_TX_RXIQCAL_TXMUX |
+ RADIO_2056_TX0);
pi->tx_rx_cal_radio_saveregs[1] =
- read_radio_reg(pi,
- RADIO_2056_RX_RXIQCAL_RXMUX |
- RADIO_2056_RX1);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXIQCAL_RXMUX |
+ RADIO_2056_RX1);
if (pi->pubpi.radiorev >= 5) {
pi->tx_rx_cal_radio_saveregs[2] =
- read_radio_reg(pi,
- RADIO_2056_RX_RXSPARE2 |
- RADIO_2056_RX1);
+ read_radio_reg(pi,
+ RADIO_2056_RX_RXSPARE2 |
+ RADIO_2056_RX1);
pi->tx_rx_cal_radio_saveregs[3] =
- read_radio_reg(pi,
- RADIO_2056_TX_TXSPARE2 |
- RADIO_2056_TX0);
+ read_radio_reg(pi,
+ RADIO_2056_TX_TXSPARE2 |
+ RADIO_2056_TX0);
}
if (CHSPEC_IS5G(pi->radio_chanspec)) {
if (pi->pubpi.radiorev >= 5) {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAA_MASTER
- | RADIO_2056_RX1);
-
- write_radio_reg(pi,
- RADIO_2056_RX_LNAA_MASTER
- | RADIO_2056_RX1, 0x40);
-
- write_radio_reg(pi,
- RADIO_2056_TX_TXSPARE2 |
- RADIO_2056_TX0, bias_a);
-
- write_radio_reg(pi,
- RADIO_2056_RX_RXSPARE2 |
- RADIO_2056_RX1, bias_a);
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX1);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER |
+ RADIO_2056_RX1, 0x40);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TXSPARE2
+ |
+ RADIO_2056_TX0, bias_a);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_RXSPARE2
+ |
+ RADIO_2056_RX1, bias_a);
} else {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAA_TUNE
- | RADIO_2056_RX1);
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX1);
offtune_val =
- (pi->
- tx_rx_cal_radio_saveregs[2] & 0xF0)
- >> 8;
+ (pi->
+ tx_rx_cal_radio_saveregs[2] &
+ 0xF0) >> 8;
offtune_val =
- (offtune_val <= 0x7) ? 0xF : 0;
+ (offtune_val <= 0x7) ? 0xF : 0;
mod_radio_reg(pi,
RADIO_2056_RX_LNAA_TUNE |
@@ -24826,33 +26747,40 @@ static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core)
} else {
if (pi->pubpi.radiorev >= 5) {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAG_MASTER
- | RADIO_2056_RX1);
-
- write_radio_reg(pi,
- RADIO_2056_RX_LNAG_MASTER
- | RADIO_2056_RX1, 0x40);
-
- write_radio_reg(pi,
- RADIO_2056_TX_TXSPARE2 |
- RADIO_2056_TX0, bias_g);
-
- write_radio_reg(pi,
- RADIO_2056_RX_RXSPARE2 |
- RADIO_2056_RX1, bias_g);
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX1);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX1, 0x40);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_TX_TXSPARE2
+ |
+ RADIO_2056_TX0, bias_g);
+
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_RXSPARE2
+ |
+ RADIO_2056_RX1, bias_g);
} else {
pi->tx_rx_cal_radio_saveregs[4] =
- read_radio_reg(pi,
- RADIO_2056_RX_LNAG_TUNE
- | RADIO_2056_RX1);
+ read_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX1);
offtune_val =
- (pi->
- tx_rx_cal_radio_saveregs[2] & 0xF0)
- >> 8;
+ (pi->
+ tx_rx_cal_radio_saveregs[2] &
+ 0xF0) >> 8;
offtune_val =
- (offtune_val <= 0x7) ? 0xF : 0;
+ (offtune_val <= 0x7) ? 0xF : 0;
mod_radio_reg(pi,
RADIO_2056_RX_LNAG_TUNE |
@@ -24876,46 +26804,54 @@ static void wlc_phy_rxcal_radio_cleanup_nphy(struct brcms_phy *pi, u8 rx_core)
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
if (rx_core == PHY_CORE_0) {
if (CHSPEC_IS5G(pi->radio_chanspec)) {
- write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP,
- pi->
- tx_rx_cal_radio_saveregs[0]);
- write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN,
- pi->
- tx_rx_cal_radio_saveregs[1]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
} else {
- write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP,
- pi->
- tx_rx_cal_radio_saveregs[0]);
- write_radio_reg(pi,
- RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN,
- pi->
- tx_rx_cal_radio_saveregs[1]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
}
} else {
if (CHSPEC_IS5G(pi->radio_chanspec)) {
- write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP,
- pi->
- tx_rx_cal_radio_saveregs[0]);
- write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN,
- pi->
- tx_rx_cal_radio_saveregs[1]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
} else {
- write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP,
- pi->
- tx_rx_cal_radio_saveregs[0]);
- write_radio_reg(pi,
- RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN,
- pi->
- tx_rx_cal_radio_saveregs[1]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP,
+ pi->
+ tx_rx_cal_radio_saveregs[0]);
+ write_radio_reg(
+ pi,
+ RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN,
+ pi->
+ tx_rx_cal_radio_saveregs[1]);
}
}
@@ -24946,37 +26882,39 @@ static void wlc_phy_rxcal_radio_cleanup_nphy(struct brcms_phy *pi, u8 rx_core)
}
if (CHSPEC_IS5G(pi->radio_chanspec)) {
- if (pi->pubpi.radiorev >= 5) {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAA_MASTER
- | RADIO_2056_RX0,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- } else {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAA_TUNE
- | RADIO_2056_RX0,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- }
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
} else {
- if (pi->pubpi.radiorev >= 5) {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAG_MASTER
- | RADIO_2056_RX0,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- } else {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAG_TUNE
- | RADIO_2056_RX0,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- }
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX0,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
}
} else {
@@ -25005,37 +26943,39 @@ static void wlc_phy_rxcal_radio_cleanup_nphy(struct brcms_phy *pi, u8 rx_core)
}
if (CHSPEC_IS5G(pi->radio_chanspec)) {
- if (pi->pubpi.radiorev >= 5) {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAA_MASTER
- | RADIO_2056_RX1,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- } else {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAA_TUNE
- | RADIO_2056_RX1,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- }
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_MASTER
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAA_TUNE
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
} else {
- if (pi->pubpi.radiorev >= 5) {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAG_MASTER
- | RADIO_2056_RX1,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- } else {
- write_radio_reg(pi,
- RADIO_2056_RX_LNAG_TUNE
- | RADIO_2056_RX1,
- pi->
- tx_rx_cal_radio_saveregs
- [4]);
- }
+ if (pi->pubpi.radiorev >= 5)
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_MASTER
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
+ else
+ write_radio_reg(
+ pi,
+ RADIO_2056_RX_LNAG_TUNE
+ | RADIO_2056_RX1,
+ pi->
+ tx_rx_cal_radio_saveregs
+ [4]);
}
}
}
@@ -25046,18 +26986,16 @@ static void wlc_phy_rxcal_physetup_nphy(struct brcms_phy *pi, u8 rx_core)
u8 tx_core;
u16 rx_antval, tx_antval;
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
tx_core = rx_core;
- } else {
+ else
tx_core = (rx_core == PHY_CORE_0) ? 1 : 0;
- }
pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa2);
pi->tx_rx_cal_phy_saveregs[1] =
- read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7);
+ read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7);
pi->tx_rx_cal_phy_saveregs[2] =
- read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5);
+ read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5);
pi->tx_rx_cal_phy_saveregs[3] = read_phy_reg(pi, 0x91);
pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x92);
pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x7a);
@@ -25122,17 +27060,19 @@ static void wlc_phy_rxcal_physetup_nphy(struct brcms_phy *pi, u8 rx_core)
NPHY_REV7_RFCTRLOVERRIDE_ID2);
wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0, 0,
NPHY_REV7_RFCTRLOVERRIDE_ID1);
- if (CHSPEC_IS40(pi->radio_chanspec)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi,
- (0x1 << 7),
- 2, 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- } else {
- wlc_phy_rfctrl_override_nphy_rev7(pi,
- (0x1 << 7),
- 0, 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- }
+ if (CHSPEC_IS40(pi->radio_chanspec))
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ 2, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+ else
+ wlc_phy_rfctrl_override_nphy_rev7(
+ pi,
+ (0x1 << 7),
+ 0, 0, 0,
+ NPHY_REV7_RFCTRLOVERRIDE_ID1);
+
wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7),
0, 0, 0,
NPHY_REV7_RFCTRLOVERRIDE_ID1);
@@ -25203,26 +27143,24 @@ wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core,
struct phy_iq_est est[PHY_CORE_MAX];
u8 tx_core;
struct nphy_iq_comp save_comp, zero_comp;
- u32 i_pwr, q_pwr, curr_pwr, optim_pwr = 0, prev_pwr = 0, thresh_pwr =
- 10000;
+ u32 i_pwr, q_pwr, curr_pwr, optim_pwr = 0, prev_pwr = 0,
+ thresh_pwr = 10000;
s16 desired_log2_pwr, actual_log2_pwr, delta_pwr;
bool gainctrl_done = false;
u8 mix_tia_gain = 3;
s8 optim_gaintbl_index = 0, prev_gaintbl_index = 0;
s8 curr_gaintbl_index = 3;
u8 gainctrl_dirn = NPHY_RXCAL_GAIN_INIT;
- struct nphy_ipa_txrxgain *nphy_rxcal_gaintbl;
+ const struct nphy_ipa_txrxgain *nphy_rxcal_gaintbl;
u16 hpvga, lpf_biq1, lpf_biq0, lna2, lna1;
int fine_gain_idx;
s8 txpwrindex;
u16 nphy_rxcal_txgain[2];
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
tx_core = rx_core;
- } else {
+ else
tx_core = 1 - rx_core;
- }
num_samps = 1024;
desired_log2_pwr = (cal_type == 0) ? 13 : 13;
@@ -25232,45 +27170,42 @@ wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core,
wlc_phy_rx_iq_coeffs_nphy(pi, 1, &zero_comp);
if (CHSPEC_IS5G(pi->radio_chanspec)) {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
mix_tia_gain = 3;
- } else if (NREV_GE(pi->pubpi.phy_rev, 4)) {
+ else if (NREV_GE(pi->pubpi.phy_rev, 4))
mix_tia_gain = 4;
- } else {
+ else
mix_tia_gain = 6;
- }
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz_rev7;
- } else {
+ else
nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz;
- }
} else {
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz_rev7;
- } else {
+ else
nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz;
- }
}
do {
hpvga = (NREV_GE(pi->pubpi.phy_rev, 7)) ?
- 0 : nphy_rxcal_gaintbl[curr_gaintbl_index].hpvga;
+ 0 : nphy_rxcal_gaintbl[curr_gaintbl_index].hpvga;
lpf_biq1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq1;
lpf_biq0 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq0;
lna2 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna2;
lna1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna1;
txpwrindex = nphy_rxcal_gaintbl[curr_gaintbl_index].txpwrindex;
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_rxgain,
- ((lpf_biq1 << 12) |
- (lpf_biq0 << 8) |
- (mix_tia_gain <<
- 4) | (lna2 << 2)
- | lna1), 0x3, 0);
- } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxgain,
+ ((lpf_biq1 << 12) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) | (lna2 << 2)
+ | lna1), 0x3, 0);
+ else
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12),
((hpvga << 12) |
(lpf_biq1 << 10) |
@@ -25278,7 +27213,6 @@ wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core,
(mix_tia_gain << 4) |
(lna2 << 2) | lna1), 0x3,
0);
- }
pi->nphy_rxcal_pwr_idx[tx_core] = txpwrindex;
@@ -25367,27 +27301,28 @@ wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core,
if (NREV_GE(pi->pubpi.phy_rev, 7)) {
fine_gain_idx = (int)lpf_biq1 + delta_pwr;
- if (fine_gain_idx + (int)lpf_biq0 > 10) {
+ if (fine_gain_idx + (int)lpf_biq0 > 10)
lpf_biq1 = 10 - lpf_biq0;
- } else {
+ else
lpf_biq1 = (u16) max(fine_gain_idx, 0);
- }
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_rxgain,
- ((lpf_biq1 << 12) |
- (lpf_biq0 << 8) |
- (mix_tia_gain << 4) |
- (lna2 << 2) | lna1), 0x3,
- 0);
+
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxgain,
+ ((lpf_biq1 << 12) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) |
+ (lna2 << 2) | lna1), 0x3,
+ 0);
} else {
hpvga = (u16) max(min(((int)hpvga) + delta_pwr, 10), 0);
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12),
- ((hpvga << 12) | (lpf_biq1 << 10) |
- (lpf_biq0 << 8) | (mix_tia_gain <<
- 4) | (lna2 <<
- 2) |
+ ((hpvga << 12) |
+ (lpf_biq1 << 10) |
+ (lpf_biq0 << 8) |
+ (mix_tia_gain << 4) |
+ (lna2 << 2) |
lna1), 0x3, 0);
-
}
if (rxgain != NULL) {
@@ -25444,9 +27379,8 @@ wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
u16 num_samps, log_num_samps = 10;
struct phy_iq_est est[PHY_CORE_MAX];
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
return 0;
- }
num_samps = (1 << log_num_samps);
@@ -25465,20 +27399,21 @@ wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
if (core_idx == 0) {
radio_addr_offset_rx = RADIO_2056_RX0;
radio_addr_offset_tx =
- (loopback_type == 0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
+ (loopback_type == 0) ? RADIO_2056_TX0 : RADIO_2056_TX1;
} else {
radio_addr_offset_rx = RADIO_2056_RX1;
radio_addr_offset_tx =
- (loopback_type == 0) ? RADIO_2056_TX1 : RADIO_2056_TX0;
+ (loopback_type == 0) ? RADIO_2056_TX1 : RADIO_2056_TX0;
}
orig_txlpf_rccal_lpc_ovr_val =
- read_radio_reg(pi,
- (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx));
+ read_radio_reg(pi,
+ (RADIO_2056_TX_TXLPF_RCCAL |
+ radio_addr_offset_tx));
orig_rxlpf_rccal_hpc_ovr_val =
- read_radio_reg(pi,
- (RADIO_2056_RX_RXLPF_RCCAL_HPC |
- radio_addr_offset_rx));
+ read_radio_reg(pi,
+ (RADIO_2056_RX_RXLPF_RCCAL_HPC |
+ radio_addr_offset_rx));
orig_dcBypass = ((read_phy_reg(pi, 0x48) >> 8) & 1);
@@ -25549,17 +27484,18 @@ wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0);
- if (core_idx == 0) {
+ if (core_idx == 0)
ref_iq_vals =
- max_t(u32, (est[0].i_pwr +
- est[0].q_pwr) >> (log_num_samps + 1),
- 1);
- } else {
+ max_t(u32, (est[0].i_pwr +
+ est[0].q_pwr) >>
+ (log_num_samps + 1),
+ 1);
+ else
ref_iq_vals =
- max_t(u32, (est[1].i_pwr +
- est[1].q_pwr) >> (log_num_samps + 1),
- 1);
- }
+ max_t(u32, (est[1].i_pwr +
+ est[1].q_pwr) >>
+ (log_num_samps + 1),
+ 1);
wlc_phy_tx_tone_nphy(pi, target_bw, NPHY_RXCAL_TONEAMP,
0, 1, false);
@@ -25568,20 +27504,19 @@ wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0);
- if (core_idx == 0) {
- target_iq_vals =
- (est[0].i_pwr + est[0].q_pwr) >> (log_num_samps +
- 1);
- } else {
+ if (core_idx == 0)
+ target_iq_vals = (est[0].i_pwr + est[0].q_pwr) >>
+ (log_num_samps + 1);
+ else
target_iq_vals =
- (est[1].i_pwr + est[1].q_pwr) >> (log_num_samps +
- 1);
- }
+ (est[1].i_pwr +
+ est[1].q_pwr) >> (log_num_samps + 1);
+
pwr_ratio = (uint) ((target_iq_vals << 16) / ref_iq_vals);
- if (rccal_stepsize == 0) {
+ if (rccal_stepsize == 0)
rccal_stepsize--;
- } else if (rccal_stepsize == 1) {
+ else if (rccal_stepsize == 1) {
last_rccal_val = rccal_val;
rccal_val += (pwr_ratio > target_pwr_ratio) ? 1 : -1;
last_pwr_ratio = pwr_ratio;
@@ -25594,21 +27529,20 @@ wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
if (rccal_stepsize == -1) {
best_rccal_val =
- (ABS((int)last_pwr_ratio - (int)target_pwr_ratio) <
- ABS((int)pwr_ratio -
- (int)target_pwr_ratio)) ? last_rccal_val :
- rccal_val;
+ (abs((int)last_pwr_ratio -
+ (int)target_pwr_ratio) <
+ abs((int)pwr_ratio -
+ (int)target_pwr_ratio)) ? last_rccal_val :
+ rccal_val;
if (CHSPEC_IS40(pi->radio_chanspec)) {
if ((best_rccal_val > 140)
- || (best_rccal_val < 135)) {
+ || (best_rccal_val < 135))
best_rccal_val = 138;
- }
} else {
if ((best_rccal_val > 142)
- || (best_rccal_val < 137)) {
+ || (best_rccal_val < 137))
best_rccal_val = 140;
- }
}
write_radio_reg(pi,
@@ -25649,7 +27583,7 @@ wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type)
return best_rccal_val - 0x80;
}
-#define WAIT_FOR_SCOPE 4000
+#define WAIT_FOR_SCOPE 4000
static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
struct nphy_txgains target_gain,
u8 cal_type, bool debug)
@@ -25687,12 +27621,12 @@ static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain);
rxcore_state = wlc_phy_rxcore_getstate_nphy(
- (struct brcms_phy_pub *) pi);
+ (struct brcms_phy_pub *) pi);
for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) {
skip_rxiqcal =
- ((rxcore_state & (1 << rx_core)) == 0) ? true : false;
+ ((rxcore_state & (1 << rx_core)) == 0) ? true : false;
wlc_phy_rxcal_physetup_nphy(pi, rx_core);
@@ -25703,7 +27637,8 @@ static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL, 0);
wlc_phy_tx_tone_nphy(pi,
- (CHSPEC_IS40(pi->radio_chanspec)) ?
+ (CHSPEC_IS40(
+ pi->radio_chanspec)) ?
NPHY_RXCAL_TONEFREQ_40MHz :
NPHY_RXCAL_TONEFREQ_20MHz,
NPHY_RXCAL_TONEAMP, 0, cal_type,
@@ -25721,23 +27656,21 @@ static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
if (rx_core == PHY_CORE_1) {
- if (rxcore_state == 1) {
+ if (rxcore_state == 1)
wlc_phy_rxcore_setstate_nphy(
(struct brcms_phy_pub *) pi, 3);
- }
wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL,
1);
best_rccal[rx_core] =
- wlc_phy_rc_sweep_nphy(pi, rx_core, 1);
+ wlc_phy_rc_sweep_nphy(pi, rx_core, 1);
pi->nphy_rccal_value = best_rccal[rx_core];
- if (rxcore_state == 1) {
+ if (rxcore_state == 1)
wlc_phy_rxcore_setstate_nphy(
(struct brcms_phy_pub *) pi,
rxcore_state);
- }
}
}
@@ -25756,18 +27689,22 @@ static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) {
rxlpf_rccal_hpc =
- (((int)best_rccal[rx_core] - 12) >> 1) + 10;
+ (((int)best_rccal[rx_core] - 12) >> 1) + 10;
txlpf_rccal_lpc = ((int)best_rccal[rx_core] - 12) + 10;
if (PHY_IPA(pi)) {
- txlpf_rccal_lpc += IS40MHZ(pi) ? 24 : 12;
- txlpf_idac = IS40MHZ(pi) ? 0x0e : 0x13;
+ txlpf_rccal_lpc +=
+ (pi->bw == WL_CHANSPEC_BW_40) ? 24 : 12;
+ txlpf_idac = (pi->bw == WL_CHANSPEC_BW_40) ?
+ 0x0e : 0x13;
WRITE_RADIO_REG2(pi, RADIO_2056, TX, rx_core,
TXLPF_IDAC_4, txlpf_idac);
}
- rxlpf_rccal_hpc = max(min_t(u8, rxlpf_rccal_hpc, 31), 0);
- txlpf_rccal_lpc = max(min_t(u8, txlpf_rccal_lpc, 31), 0);
+ rxlpf_rccal_hpc = max(min_t(u8, rxlpf_rccal_hpc, 31),
+ 0);
+ txlpf_rccal_lpc = max(min_t(u8, txlpf_rccal_lpc, 31),
+ 0);
write_radio_reg(pi, (RADIO_2056_RX_RXLPF_RCCAL_HPC |
((rx_core ==
@@ -25787,21 +27724,21 @@ static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi,
wlc_phy_resetcca_nphy(pi);
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_rxgain,
- 0, 0x3, 1);
- } else {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
+ wlc_phy_rfctrl_override_1tomany_nphy(
+ pi,
+ NPHY_REV7_RfctrlOverride_cmd_rxgain,
+ 0, 0x3, 1);
+ else
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1);
- }
+
wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX);
wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16,
gain_save);
- if (NREV_GE(pi->pubpi.phy_rev, 4)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 4))
pi->phyhang_avoid = phyhang_avoid_state;
- }
wlc_phy_stay_in_carriersearch_nphy(pi, false);
@@ -25835,10 +27772,8 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
wlc_phy_stay_in_carriersearch_nphy(pi, true);
- if (NREV_LT(pi->pubpi.phy_rev, 2)) {
-
+ if (NREV_LT(pi->pubpi.phy_rev, 2))
wlc_phy_reapply_txcal_coeffs_nphy(pi);
- }
wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save);
@@ -25874,19 +27809,16 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
((0x1 << 1) | (0x1 << 2)));
or_phy_reg(pi, 0xa5, ((0x1 << 1) | (0x1 << 2)));
- if (((pi->nphy_rxcalparams) & 0xff000000)) {
-
+ if (((pi->nphy_rxcalparams) & 0xff000000))
write_phy_reg(pi,
(rx_core == PHY_CORE_0) ? 0x91 : 0x92,
- (CHSPEC_IS5G(pi->radio_chanspec) ? 0x140 :
- 0x110));
- } else {
-
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0x140 : 0x110));
+ else
write_phy_reg(pi,
(rx_core == PHY_CORE_0) ? 0x91 : 0x92,
- (CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 :
- 0x120));
- }
+ (CHSPEC_IS5G(pi->radio_chanspec) ?
+ 0x180 : 0x120));
write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 : 0x92,
(CHSPEC_IS5G(pi->radio_chanspec) ? 0x148 :
@@ -25926,7 +27858,7 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
use_hpf_num = 1;
curr_hpf = curr_hpf1;
actual_log2_pwr =
- wlc_phy_nbits(tot_pwr[2]);
+ wlc_phy_nbits(tot_pwr[2]);
} else {
if (tot_pwr[0] > 10000) {
curr_lna = lna_vals[1];
@@ -25935,7 +27867,8 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
use_hpf_num = 1;
curr_hpf = curr_hpf1;
actual_log2_pwr =
- wlc_phy_nbits(tot_pwr[1]);
+ wlc_phy_nbits(
+ tot_pwr[1]);
} else {
curr_lna = lna_vals[0];
curr_hpf1 = hpf1_vals[0];
@@ -25943,18 +27876,18 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
use_hpf_num = 2;
curr_hpf = curr_hpf2;
actual_log2_pwr =
- wlc_phy_nbits(tot_pwr[0]);
+ wlc_phy_nbits(
+ tot_pwr[0]);
}
}
hpf_change = desired_log2_pwr - actual_log2_pwr;
curr_hpf += hpf_change;
curr_hpf = max(min_t(u16, curr_hpf, 10), 0);
- if (use_hpf_num == 1) {
+ if (use_hpf_num == 1)
curr_hpf1 = curr_hpf;
- } else {
+ else
curr_hpf2 = curr_hpf;
- }
}
wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10),
@@ -25967,15 +27900,12 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
if (first_playtone) {
bcmerror = wlc_phy_tx_tone_nphy(pi, 4000,
- (u16) (pi->
- nphy_rxcalparams
- &
- 0xffff),
- 0, 0, true);
+ (u16) (pi->nphy_rxcalparams &
+ 0xffff), 0, 0, true);
first_playtone = false;
} else {
- phy_bw =
- (CHSPEC_IS40(pi->radio_chanspec)) ? 40 : 20;
+ phy_bw = (CHSPEC_IS40(pi->radio_chanspec)) ?
+ 40 : 20;
wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff,
0, 0, 0, true);
}
@@ -25986,12 +27916,10 @@ wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi,
wlc_phy_rx_iq_est_nphy(pi, est,
num_samps, 32,
0);
- i_pwr =
- (est[rx_core].i_pwr +
- num_samps / 2) / num_samps;
- q_pwr =
- (est[rx_core].q_pwr +
- num_samps / 2) / num_samps;
+ i_pwr = (est[rx_core].i_pwr +
+ num_samps / 2) / num_samps;
+ q_pwr = (est[rx_core].q_pwr +
+ num_samps / 2) / num_samps;
tot_pwr[gain_pass] = i_pwr + q_pwr;
} else {
@@ -26038,1350 +27966,14 @@ int
wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain,
u8 cal_type, bool debug)
{
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
cal_type = 0;
- }
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
return wlc_phy_cal_rxiq_nphy_rev3(pi, target_gain, cal_type,
debug);
- } else {
+ else
return wlc_phy_cal_rxiq_nphy_rev2(pi, target_gain, debug);
- }
-}
-
-static void wlc_phy_extpa_set_tx_digi_filts_nphy(struct brcms_phy *pi)
-{
- int j, type = 2;
- u16 addr_offset = 0x2c5;
-
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, addr_offset + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]);
- }
-}
-
-static void wlc_phy_ipa_set_tx_digi_filts_nphy(struct brcms_phy *pi)
-{
- int j, type;
- u16 addr_offset[] = { 0x186, 0x195,
- 0x2c5
- };
-
- for (type = 0; type < 3; type++) {
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, addr_offset[type] + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]);
- }
- }
-
- if (IS40MHZ(pi)) {
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, 0x186 + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]);
- }
- } else {
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, 0x186 + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[5]
- [j]);
- }
- }
-
- if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) {
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, 0x2c5 + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[6]
- [j]);
- }
- }
- }
-}
-
-static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi)
-{
- int j;
-
- if (IS40MHZ(pi)) {
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, 0x195 + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[4][j]);
- }
- } else {
- for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) {
- write_phy_reg(pi, 0x186 + j,
- NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]);
- }
- }
-}
-
-static u16 wlc_phy_ipa_get_bbmult_nphy(struct brcms_phy *pi)
-{
- u16 m0m1;
-
- wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1);
-
- return m0m1;
-}
-
-static void wlc_phy_ipa_set_bbmult_nphy(struct brcms_phy *pi, u8 m0, u8 m1)
-{
- u16 m0m1 = (u16) ((m0 << 8) | m1);
-
- wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m0m1);
- wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &m0m1);
-}
-
-static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi)
-{
- u32 *tx_pwrctrl_tbl = NULL;
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- if ((pi->pubpi.radiorev == 4)
- || (pi->pubpi.radiorev == 6)) {
-
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_ipa_2g_2057rev4n6;
- } else if (pi->pubpi.radiorev == 3) {
-
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_ipa_2g_2057rev3;
- } else if (pi->pubpi.radiorev == 5) {
-
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_ipa_2g_2057rev5;
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_ipa_2g_2057rev7;
- }
-
- } else if (NREV_IS(pi->pubpi.phy_rev, 6)) {
-
- tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6;
- } else if (NREV_IS(pi->pubpi.phy_rev, 5)) {
-
- tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5;
- } else {
-
- tx_pwrctrl_tbl = nphy_tpc_txgain_ipa;
- }
-
- } else {
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if ((pi->pubpi.radiorev == 3) ||
- (pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
-
- tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g_2057;
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- tx_pwrctrl_tbl =
- nphy_tpc_txgain_ipa_5g_2057rev7;
- }
-
- } else {
- tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g;
- }
- }
-
- return tx_pwrctrl_tbl;
-}
-
-static void
-wlc_phy_papd_cal_setup_nphy(struct brcms_phy *pi,
- struct nphy_papd_restore_state *state, u8 core)
-{
- s32 tone_freq;
- u8 off_core;
- u16 mixgain = 0;
-
- off_core = core ^ 0x1;
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- if (NREV_IS(pi->pubpi.phy_rev, 7)
- || NREV_GE(pi->pubpi.phy_rev, 8)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7),
- wlc_phy_read_lpf_bw_ctl_nphy
- (pi, 0), 0, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- }
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (pi->pubpi.radiorev == 5) {
- mixgain = (core == 0) ? 0x20 : 0x00;
-
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- mixgain = 0x00;
-
- } else if ((pi->pubpi.radiorev <= 4)
- || (pi->pubpi.radiorev == 6)) {
-
- mixgain = 0x00;
- }
-
- } else {
- if ((pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
-
- mixgain = 0x50;
- } else if ((pi->pubpi.radiorev == 3)
- || (pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- mixgain = 0x0;
- }
- }
-
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11),
- mixgain, (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
-
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_tx_pu,
- 1, (1 << core), 0);
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_tx_pu,
- 0, (1 << off_core), 0);
-
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
- 0, 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
-
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5),
- 0, (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0,
- (1 << core), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
-
- state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ?
- 0xa6 : 0xa7);
- state->afeoverride[core] =
- read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5);
- state->afectrl[off_core] =
- read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa7 : 0xa6);
- state->afeoverride[off_core] =
- read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa5 : 0x8f);
-
- mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7),
- (0x1 << 2), 0);
- mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
- 0xa5), (0x1 << 2), (0x1 << 2));
-
- mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa7 : 0xa6),
- (0x1 << 2), (0x1 << 2));
- mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa5 :
- 0x8f), (0x1 << 2), (0x1 << 2));
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- state->pwrup[core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_PWRUP);
- state->atten[core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_ATTEN);
- state->pwrup[off_core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_2G_PWRUP);
- state->atten[off_core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_2G_ATTEN);
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_PWRUP, 0xc);
-
- if ((pi->pubpi.radiorev == 3) ||
- (pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_ATTEN, 0xf0);
-
- } else if (pi->pubpi.radiorev == 5) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_ATTEN,
- (core == 0) ? 0xf7 : 0xf2);
-
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_ATTEN, 0xf0);
-
- }
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_2G_PWRUP, 0x0);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_2G_ATTEN, 0xff);
-
- } else {
- state->pwrup[core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_PWRUP);
- state->atten[core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_ATTEN);
- state->pwrup[off_core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_5G_PWRUP);
- state->atten[off_core] =
- READ_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_5G_ATTEN);
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_PWRUP, 0xc);
-
- if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_ATTEN, 0xf4);
-
- } else {
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_ATTEN, 0xf0);
- }
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_5G_PWRUP, 0x0);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core,
- TXRXCOUPLE_5G_ATTEN, 0xff);
- }
-
- tone_freq = 4000;
-
- wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (1) << 13);
-
- mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_OFF) << 0);
-
- mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (0) << 13);
-
- } else {
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 0);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0, 0);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 0);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 1, 0x3, 0);
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0x3, 0);
-
- state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ?
- 0xa6 : 0xa7);
- state->afeoverride[core] =
- read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5);
-
- mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7),
- (0x1 << 0) | (0x1 << 1) | (0x1 << 2), 0);
- mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
- 0xa5),
- (0x1 << 0) |
- (0x1 << 1) |
- (0x1 << 2), (0x1 << 0) | (0x1 << 1) | (0x1 << 2));
-
- state->vga_master[core] =
- READ_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER);
- WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, 0x2b);
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- state->fbmix[core] =
- READ_RADIO_REG2(pi, RADIO_2056, RX, core,
- TXFBMIX_G);
- state->intpa_master[core] =
- READ_RADIO_REG2(pi, RADIO_2056, TX, core,
- INTPAG_MASTER);
-
- WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_G,
- 0x03);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- INTPAG_MASTER, 0x04);
- } else {
- state->fbmix[core] =
- READ_RADIO_REG2(pi, RADIO_2056, RX, core,
- TXFBMIX_A);
- state->intpa_master[core] =
- READ_RADIO_REG2(pi, RADIO_2056, TX, core,
- INTPAA_MASTER);
-
- WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_A,
- 0x03);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- INTPAA_MASTER, 0x04);
-
- }
-
- tone_freq = 4000;
-
- wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (1) << 0);
-
- mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (0) << 0);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0);
- }
-}
-
-static void
-wlc_phy_papd_cal_cleanup_nphy(struct brcms_phy *pi,
- struct nphy_papd_restore_state *state)
-{
- u8 core;
-
- wlc_phy_stopplayback_nphy(pi);
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_PWRUP, 0);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_2G_ATTEN,
- state->atten[core]);
- } else {
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_PWRUP, 0);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TXRXCOUPLE_5G_ATTEN,
- state->atten[core]);
- }
- }
-
- if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2),
- 1, 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- } else {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2),
- 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- }
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1),
- 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 1, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID2);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
-
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
-
- write_phy_reg(pi, (core == PHY_CORE_0) ?
- 0xa6 : 0xa7, state->afectrl[core]);
- write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f :
- 0xa5, state->afeoverride[core]);
- }
-
- wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff,
- (state->mm & 0xff));
-
- if (NREV_IS(pi->pubpi.phy_rev, 7)
- || NREV_GE(pi->pubpi.phy_rev, 8)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7), 0, 0,
- 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID1);
- }
- } else {
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1);
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 0x3, 1);
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 1);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 0, 0x3, 1);
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 0, 0x3, 1);
-
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
-
- WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER,
- state->vga_master[core]);
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- WRITE_RADIO_REG2(pi, RADIO_2056, RX, core,
- TXFBMIX_G, state->fbmix[core]);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- INTPAG_MASTER,
- state->intpa_master[core]);
- } else {
- WRITE_RADIO_REG2(pi, RADIO_2056, RX, core,
- TXFBMIX_A, state->fbmix[core]);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- INTPAA_MASTER,
- state->intpa_master[core]);
- }
-
- write_phy_reg(pi, (core == PHY_CORE_0) ?
- 0xa6 : 0xa7, state->afectrl[core]);
- write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f :
- 0xa5, state->afeoverride[core]);
- }
-
- wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff,
- (state->mm & 0xff));
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 1);
- }
-}
-
-static void
-wlc_phy_a1_nphy(struct brcms_phy *pi, u8 core, u32 winsz, u32 start,
- u32 end)
-{
- u32 *buf, *src, *dst, sz;
-
- sz = end - start + 1;
-
- buf = kmalloc(2 * sizeof(u32) * NPHY_PAPD_EPS_TBL_SIZE, GFP_ATOMIC);
- if (NULL == buf) {
- return;
- }
-
- src = buf;
- dst = buf + NPHY_PAPD_EPS_TBL_SIZE;
-
- wlc_phy_table_read_nphy(pi,
- (core ==
- PHY_CORE_0 ? NPHY_TBL_ID_EPSILONTBL0 :
- NPHY_TBL_ID_EPSILONTBL1),
- NPHY_PAPD_EPS_TBL_SIZE, 0, 32, src);
-
- do {
- u32 phy_a1, phy_a2;
- s32 phy_a3, phy_a4, phy_a5, phy_a6, phy_a7;
-
- phy_a1 = end - min(end, (winsz >> 1));
- phy_a2 = min_t(u32, NPHY_PAPD_EPS_TBL_SIZE - 1, end + (winsz >> 1));
- phy_a3 = phy_a2 - phy_a1 + 1;
- phy_a6 = 0;
- phy_a7 = 0;
-
- do {
- wlc_phy_papd_decode_epsilon(src[phy_a2], &phy_a4,
- &phy_a5);
- phy_a6 += phy_a4;
- phy_a7 += phy_a5;
- } while (phy_a2-- != phy_a1);
-
- phy_a6 /= phy_a3;
- phy_a7 /= phy_a3;
- dst[end] = ((u32) phy_a7 << 13) | ((u32) phy_a6 & 0x1fff);
- } while (end-- != start);
-
- wlc_phy_table_write_nphy(pi,
- (core ==
- PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 :
- NPHY_TBL_ID_EPSILONTBL1, sz, start, 32, dst);
-
- kfree(buf);
-}
-
-static void
-wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains,
- enum phy_cal_mode cal_mode, u8 core)
-{
- u16 phy_a1, phy_a2, phy_a3;
- u16 phy_a4, phy_a5;
- bool phy_a6;
- u8 phy_a7, m[2];
- u32 phy_a8 = 0;
- struct nphy_txgains phy_a9;
-
- if (NREV_LT(pi->pubpi.phy_rev, 3))
- return;
-
- phy_a7 = (core == PHY_CORE_0) ? 1 : 0;
-
- phy_a6 = ((cal_mode == CAL_GCTRL)
- || (cal_mode == CAL_SOFT)) ? true : false;
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- phy_a9 = wlc_phy_get_tx_gain_nphy(pi);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- phy_a5 = ((phy_a9.txlpf[core] << 15) |
- (phy_a9.txgm[core] << 12) |
- (phy_a9.pga[core] << 8) |
- (txgains->gains.pad[core] << 3) |
- (phy_a9.ipa[core]));
- } else {
- phy_a5 = ((phy_a9.txlpf[core] << 15) |
- (phy_a9.txgm[core] << 12) |
- (txgains->gains.pga[core] << 8) |
- (phy_a9.pad[core] << 3) | (phy_a9.ipa[core]));
- }
-
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_txgain,
- phy_a5, (1 << core), 0);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if ((pi->pubpi.radiorev <= 4)
- || (pi->pubpi.radiorev == 6)) {
-
- m[core] = IS40MHZ(pi) ? 60 : 79;
- } else {
-
- m[core] = IS40MHZ(pi) ? 45 : 64;
- }
-
- } else {
- m[core] = IS40MHZ(pi) ? 75 : 107;
- }
-
- m[phy_a7] = 0;
- wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]);
-
- phy_a2 = 63;
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if ((pi->pubpi.radiorev == 4)
- || (pi->pubpi.radiorev == 6)) {
- phy_a1 = 30;
- phy_a3 = 30;
- } else {
- phy_a1 = 25;
- phy_a3 = 25;
- }
- } else {
- if ((pi->pubpi.radiorev == 5)
- || (pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
- phy_a1 = 25;
- phy_a3 = 25;
- } else {
- phy_a1 = 35;
- phy_a3 = 35;
- }
- }
-
- if (cal_mode == CAL_GCTRL) {
- if ((pi->pubpi.radiorev == 5)
- && (CHSPEC_IS2G(pi->radio_chanspec))) {
- phy_a1 = 55;
- } else if (((pi->pubpi.radiorev == 7) &&
- (CHSPEC_IS2G(pi->radio_chanspec))) ||
- ((pi->pubpi.radiorev == 8) &&
- (CHSPEC_IS2G(pi->radio_chanspec)))) {
- phy_a1 = 60;
- } else {
- phy_a1 = 63;
- }
-
- } else if ((cal_mode != CAL_FULL) && (cal_mode != CAL_SOFT)) {
-
- phy_a1 = 35;
- phy_a3 = 35;
- }
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (1) << 0);
-
- mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (0) << 0);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (1) << 13);
-
- mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (0) << 13);
-
- write_phy_reg(pi, 0x2a1, 0x80);
- write_phy_reg(pi, 0x2a2, 0x100);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x7 << 4), (11) << 4);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x7 << 8), (11) << 8);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x7 << 0), (0x3) << 0);
-
- write_phy_reg(pi, 0x2e5, 0x20);
-
- mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0);
-
- mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0);
-
- mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8);
-
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
- 1, ((core == 0) ? 1 : 2), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
- 0, ((core == 0) ? 2 : 1), 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
-
- write_phy_reg(pi, 0x2be, 1);
- SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000);
-
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3),
- 0, 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
-
- wlc_phy_table_write_nphy(pi,
- (core ==
- PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0
- : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3,
- 32, &phy_a8);
-
- if (cal_mode != CAL_GCTRL) {
- if (CHSPEC_IS5G(pi->radio_chanspec)) {
- wlc_phy_a1_nphy(pi, core, 5, 0, 35);
- }
- }
-
- wlc_phy_rfctrl_override_1tomany_nphy(pi,
- NPHY_REV7_RfctrlOverride_cmd_txgain,
- phy_a5, (1 << core), 1);
-
- } else {
-
- if (txgains) {
- if (txgains->useindex) {
- phy_a4 = 15 - ((txgains->index) >> 3);
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (NREV_GE(pi->pubpi.phy_rev, 6))
- phy_a5 = 0x00f7 | (phy_a4 << 8);
-
- else
- if (NREV_IS(pi->pubpi.phy_rev, 5))
- phy_a5 = 0x10f7 | (phy_a4 << 8);
- else
- phy_a5 = 0x50f7 | (phy_a4 << 8);
- } else {
- phy_a5 = 0x70f7 | (phy_a4 << 8);
- }
- wlc_phy_rfctrl_override_nphy(pi,
- (0x1 << 13),
- phy_a5,
- (1 << core), 0);
- } else {
- wlc_phy_rfctrl_override_nphy(pi,
- (0x1 << 13),
- 0x5bf7,
- (1 << core), 0);
- }
- }
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- m[core] = IS40MHZ(pi) ? 45 : 64;
- } else {
- m[core] = IS40MHZ(pi) ? 75 : 107;
- }
-
- m[phy_a7] = 0;
- wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]);
-
- phy_a2 = 63;
-
- if (cal_mode == CAL_FULL) {
- phy_a1 = 25;
- phy_a3 = 25;
- } else if (cal_mode == CAL_SOFT) {
- phy_a1 = 25;
- phy_a3 = 25;
- } else if (cal_mode == CAL_GCTRL) {
- phy_a1 = 63;
- phy_a3 = 25;
- } else {
-
- phy_a1 = 25;
- phy_a3 = 25;
- }
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (1) << 0);
-
- mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (0) << 0);
-
- if (NREV_GE(pi->pubpi.phy_rev, 6)) {
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (1) << 13);
-
- mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (0) << 13);
-
- write_phy_reg(pi, 0x2a1, 0x20);
- write_phy_reg(pi, 0x2a2, 0x60);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0xf << 4), (9) << 4);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0xf << 8), (9) << 8);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0xf << 0), (0x2) << 0);
-
- write_phy_reg(pi, 0x2e5, 0x20);
- } else {
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 11), (1) << 11);
-
- mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 11), (0) << 11);
-
- write_phy_reg(pi, 0x2a1, 0x80);
- write_phy_reg(pi, 0x2a2, 0x600);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x7 << 4), (0) << 4);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x7 << 8), (0) << 8);
-
- mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x7 << 0), (0x3) << 0);
-
- mod_phy_reg(pi, 0x2a0, (0x3f << 8), (0x20) << 8);
-
- }
-
- mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0);
-
- mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0);
-
- mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0x3, 0);
-
- write_phy_reg(pi, 0x2be, 1);
- SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000);
-
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0);
-
- wlc_phy_table_write_nphy(pi,
- (core ==
- PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0
- : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3,
- 32, &phy_a8);
-
- if (cal_mode != CAL_GCTRL) {
- wlc_phy_a1_nphy(pi, core, 5, 0, 40);
- }
- }
-}
-
-static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core)
-{
- int phy_a1;
- int phy_a2;
- bool phy_a3;
- struct nphy_ipa_txcalgains phy_a4;
- bool phy_a5 = false;
- bool phy_a6 = true;
- s32 phy_a7, phy_a8;
- u32 phy_a9;
- int phy_a10;
- bool phy_a11 = false;
- int phy_a12;
- u8 phy_a13 = 0;
- u8 phy_a14;
- u8 *phy_a15 = NULL;
-
- phy_a4.useindex = true;
- phy_a12 = start_gain;
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
-
- phy_a2 = 20;
- phy_a1 = 1;
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (pi->pubpi.radiorev == 5) {
-
- phy_a15 = pad_gain_codes_used_2057rev5;
- phy_a13 = sizeof(pad_gain_codes_used_2057rev5) /
- sizeof(pad_gain_codes_used_2057rev5[0]) - 1;
-
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- phy_a15 = pad_gain_codes_used_2057rev7;
- phy_a13 = sizeof(pad_gain_codes_used_2057rev7) /
- sizeof(pad_gain_codes_used_2057rev7[0]) - 1;
-
- } else {
-
- phy_a15 = pad_all_gain_codes_2057;
- phy_a13 = sizeof(pad_all_gain_codes_2057) /
- sizeof(pad_all_gain_codes_2057[0]) - 1;
- }
-
- } else {
-
- phy_a15 = pga_all_gain_codes_2057;
- phy_a13 = sizeof(pga_all_gain_codes_2057) /
- sizeof(pga_all_gain_codes_2057[0]) - 1;
- }
-
- phy_a14 = 0;
-
- for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) {
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- phy_a4.gains.pad[core] =
- (u16) phy_a15[phy_a12];
- } else {
- phy_a4.gains.pga[core] =
- (u16) phy_a15[phy_a12];
- }
-
- wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core);
-
- wlc_phy_table_read_nphy(pi,
- (core ==
- PHY_CORE_0 ?
- NPHY_TBL_ID_EPSILONTBL0 :
- NPHY_TBL_ID_EPSILONTBL1), 1,
- 63, 32, &phy_a9);
-
- wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8);
-
- phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) ||
- (phy_a8 == 4095) || (phy_a8 == -4096));
-
- if (!phy_a6 && (phy_a3 != phy_a5)) {
- if (!phy_a3) {
- phy_a12 -= (u8) phy_a1;
- }
- phy_a11 = true;
- break;
- }
-
- if (phy_a3)
- phy_a12 += (u8) phy_a1;
- else
- phy_a12 -= (u8) phy_a1;
-
- if ((phy_a12 < phy_a14) || (phy_a12 > phy_a13)) {
- if (phy_a12 < phy_a14) {
- phy_a12 = phy_a14;
- } else {
- phy_a12 = phy_a13;
- }
- phy_a11 = true;
- break;
- }
-
- phy_a6 = false;
- phy_a5 = phy_a3;
- }
-
- } else {
- phy_a2 = 10;
- phy_a1 = 8;
- for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) {
- phy_a4.index = (u8) phy_a12;
- wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core);
-
- wlc_phy_table_read_nphy(pi,
- (core ==
- PHY_CORE_0 ?
- NPHY_TBL_ID_EPSILONTBL0 :
- NPHY_TBL_ID_EPSILONTBL1), 1,
- 63, 32, &phy_a9);
-
- wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8);
-
- phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) ||
- (phy_a8 == 4095) || (phy_a8 == -4096));
-
- if (!phy_a6 && (phy_a3 != phy_a5)) {
- if (!phy_a3) {
- phy_a12 -= (u8) phy_a1;
- }
- phy_a11 = true;
- break;
- }
-
- if (phy_a3)
- phy_a12 += (u8) phy_a1;
- else
- phy_a12 -= (u8) phy_a1;
-
- if ((phy_a12 < 0) || (phy_a12 > 127)) {
- if (phy_a12 < 0) {
- phy_a12 = 0;
- } else {
- phy_a12 = 127;
- }
- phy_a11 = true;
- break;
- }
-
- phy_a6 = false;
- phy_a5 = phy_a3;
- }
-
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- return (u8) phy_a15[phy_a12];
- } else {
- return (u8) phy_a12;
- }
-
-}
-
-static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal)
-{
- struct nphy_ipa_txcalgains phy_b1[2];
- struct nphy_papd_restore_state phy_b2;
- bool phy_b3;
- u8 phy_b4;
- u8 phy_b5;
- s16 phy_b6, phy_b7, phy_b8;
- u16 phy_b9;
- s16 phy_b10, phy_b11, phy_b12;
-
- phy_b11 = 0;
- phy_b12 = 0;
- phy_b7 = 0;
- phy_b8 = 0;
- phy_b6 = 0;
-
- if (pi->nphy_papd_skip == 1)
- return;
-
- phy_b3 =
- (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC));
- if (!phy_b3) {
- wlapi_suspend_mac_and_wait(pi->sh->physhim);
- }
-
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- pi->nphy_force_papd_cal = false;
-
- for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++)
- pi->nphy_papd_tx_gain_at_last_cal[phy_b5] =
- wlc_phy_txpwr_idx_cur_get_nphy(pi, phy_b5);
-
- pi->nphy_papd_last_cal = pi->sh->now;
- pi->nphy_papd_recal_counter++;
-
- if (NORADIO_ENAB(pi->pubpi))
- return;
-
- phy_b4 = pi->nphy_txpwrctrl;
- wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF);
-
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL0, 64, 0, 32,
- nphy_papd_scaltbl);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL1, 64, 0, 32,
- nphy_papd_scaltbl);
-
- phy_b9 = read_phy_reg(pi, 0x01);
- mod_phy_reg(pi, 0x01, (0x1 << 15), 0);
-
- for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
- s32 i, val = 0;
- for (i = 0; i < 64; i++) {
- wlc_phy_table_write_nphy(pi,
- ((phy_b5 ==
- PHY_CORE_0) ?
- NPHY_TBL_ID_EPSILONTBL0 :
- NPHY_TBL_ID_EPSILONTBL1), 1,
- i, 32, &val);
- }
- }
-
- wlc_phy_ipa_restore_tx_digi_filts_nphy(pi);
-
- phy_b2.mm = wlc_phy_ipa_get_bbmult_nphy(pi);
- for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
- wlc_phy_papd_cal_setup_nphy(pi, &phy_b2, phy_b5);
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
-
- if ((pi->pubpi.radiorev == 3)
- || (pi->pubpi.radiorev == 4)
- || (pi->pubpi.radiorev == 6)) {
-
- pi->nphy_papd_cal_gain_index[phy_b5] =
- 23;
-
- } else if (pi->pubpi.radiorev == 5) {
-
- pi->nphy_papd_cal_gain_index[phy_b5] =
- 0;
- pi->nphy_papd_cal_gain_index[phy_b5] =
- wlc_phy_a3_nphy(pi,
- pi->
- nphy_papd_cal_gain_index
- [phy_b5], phy_b5);
-
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
-
- pi->nphy_papd_cal_gain_index[phy_b5] =
- 0;
- pi->nphy_papd_cal_gain_index[phy_b5] =
- wlc_phy_a3_nphy(pi,
- pi->
- nphy_papd_cal_gain_index
- [phy_b5], phy_b5);
-
- }
-
- phy_b1[phy_b5].gains.pad[phy_b5] =
- pi->nphy_papd_cal_gain_index[phy_b5];
-
- } else {
- pi->nphy_papd_cal_gain_index[phy_b5] = 0;
- pi->nphy_papd_cal_gain_index[phy_b5] =
- wlc_phy_a3_nphy(pi,
- pi->
- nphy_papd_cal_gain_index
- [phy_b5], phy_b5);
- phy_b1[phy_b5].gains.pga[phy_b5] =
- pi->nphy_papd_cal_gain_index[phy_b5];
- }
- } else {
- phy_b1[phy_b5].useindex = true;
- phy_b1[phy_b5].index = 16;
- phy_b1[phy_b5].index =
- wlc_phy_a3_nphy(pi, phy_b1[phy_b5].index, phy_b5);
-
- pi->nphy_papd_cal_gain_index[phy_b5] =
- 15 - ((phy_b1[phy_b5].index) >> 3);
- }
-
- switch (pi->nphy_papd_cal_type) {
- case 0:
- wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_FULL, phy_b5);
- break;
- case 1:
- wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_SOFT, phy_b5);
- break;
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2);
- }
- }
-
- if (NREV_LT(pi->pubpi.phy_rev, 7)) {
- wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2);
- }
-
- for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) {
- int eps_offset = 0;
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- if (pi->pubpi.radiorev == 3) {
- eps_offset = -2;
- } else if (pi->pubpi.radiorev == 5) {
- eps_offset = 3;
- } else {
- eps_offset = -1;
- }
- } else {
- eps_offset = 2;
- }
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- phy_b8 = phy_b1[phy_b5].gains.pad[phy_b5];
- phy_b10 = 0;
- if ((pi->pubpi.radiorev == 3) ||
- (pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
- phy_b12 =
- -
- (nphy_papd_padgain_dlt_2g_2057rev3n4
- [phy_b8]
- + 1) / 2;
- phy_b10 = -1;
- } else if (pi->pubpi.radiorev == 5) {
- phy_b12 =
- -(nphy_papd_padgain_dlt_2g_2057rev5
- [phy_b8]
- + 1) / 2;
- } else if ((pi->pubpi.radiorev == 7) ||
- (pi->pubpi.radiorev == 8)) {
- phy_b12 =
- -(nphy_papd_padgain_dlt_2g_2057rev7
- [phy_b8]
- + 1) / 2;
- }
- } else {
- phy_b7 = phy_b1[phy_b5].gains.pga[phy_b5];
- if ((pi->pubpi.radiorev == 3) ||
- (pi->pubpi.radiorev == 4) ||
- (pi->pubpi.radiorev == 6)) {
- phy_b11 =
- -(nphy_papd_pgagain_dlt_5g_2057
- [phy_b7]
- + 1) / 2;
- } else if ((pi->pubpi.radiorev == 7)
- || (pi->pubpi.radiorev == 8)) {
- phy_b11 =
- -(nphy_papd_pgagain_dlt_5g_2057rev7
- [phy_b7]
- + 1) / 2;
- }
-
- phy_b10 = -9;
- }
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- phy_b6 =
- -60 + 27 + eps_offset + phy_b12 + phy_b10;
- } else {
- phy_b6 =
- -60 + 27 + eps_offset + phy_b11 + phy_b10;
- }
-
- mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 :
- 0x29c, (0x1ff << 7), (phy_b6) << 7);
-
- pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6;
- } else {
- if (NREV_LT(pi->pubpi.phy_rev, 5)) {
- eps_offset = 4;
- } else {
- eps_offset = 2;
- }
-
- phy_b7 = 15 - ((phy_b1[phy_b5].index) >> 3);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- phy_b11 =
- -(nphy_papd_pga_gain_delta_ipa_2g[phy_b7] +
- 1) / 2;
- phy_b10 = 0;
- } else {
- phy_b11 =
- -(nphy_papd_pga_gain_delta_ipa_5g[phy_b7] +
- 1) / 2;
- phy_b10 = -9;
- }
-
- phy_b6 = -60 + 27 + eps_offset + phy_b11 + phy_b10;
-
- mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 :
- 0x29c, (0x1ff << 7), (phy_b6) << 7);
-
- pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6;
- }
- }
-
- mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
-
- mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 :
- 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0);
-
- if (NREV_GE(pi->pubpi.phy_rev, 6)) {
- mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (0) << 13);
-
- mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 13), (0) << 13);
-
- } else {
- mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 11), (0) << 11);
-
- mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 :
- 0x2a4, (0x1 << 11), (0) << 11);
-
- }
- pi->nphy_papdcomp = NPHY_PAPD_COMP_ON;
-
- write_phy_reg(pi, 0x01, phy_b9);
-
- wlc_phy_ipa_set_tx_digi_filts_nphy(pi);
-
- wlc_phy_txpwrctrl_enable_nphy(pi, phy_b4);
- if (phy_b4 == PHY_TPC_HW_OFF) {
- wlc_phy_txpwr_index_nphy(pi, (1 << 0),
- (s8) (pi->nphy_txpwrindex[0].
- index_internal), false);
- wlc_phy_txpwr_index_nphy(pi, (1 << 1),
- (s8) (pi->nphy_txpwrindex[1].
- index_internal), false);
- }
-
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-
- if (!phy_b3) {
- wlapi_enable_mac(pi->sh->physhim);
- }
}
void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
@@ -27423,11 +28015,10 @@ void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
}
}
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 7))
txpi[0] = txpi[1] = 30;
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ else if (NREV_GE(pi->pubpi.phy_rev, 3))
txpi[0] = txpi[1] = 40;
- }
if (NREV_LT(pi->pubpi.phy_rev, 7)) {
@@ -27447,37 +28038,36 @@ void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
if (NREV_GE(phyrev, 3)) {
if (PHY_IPA(pi)) {
u32 *tx_gaintbl =
- wlc_phy_get_ipa_gaintbl_nphy(pi);
+ wlc_phy_get_ipa_gaintbl_nphy(pi);
txgain = tx_gaintbl[txpi[core]];
} else {
if (CHSPEC_IS5G(pi->radio_chanspec)) {
if (NREV_IS(phyrev, 3)) {
txgain =
- nphy_tpc_5GHz_txgain_rev3
- [txpi[core]];
+ nphy_tpc_5GHz_txgain_rev3
+ [txpi[core]];
} else if (NREV_IS(phyrev, 4)) {
- txgain =
- (pi->srom_fem5g.extpagain ==
- 3) ?
- nphy_tpc_5GHz_txgain_HiPwrEPA
- [txpi[core]] :
- nphy_tpc_5GHz_txgain_rev4
- [txpi[core]];
+ txgain = (
+ pi->srom_fem5g.extpagain ==
+ 3) ?
+ nphy_tpc_5GHz_txgain_HiPwrEPA
+ [txpi[core]] :
+ nphy_tpc_5GHz_txgain_rev4
+ [txpi[core]];
} else {
txgain =
- nphy_tpc_5GHz_txgain_rev5
- [txpi[core]];
+ nphy_tpc_5GHz_txgain_rev5
+ [txpi[core]];
}
} else {
if (NREV_GE(phyrev, 5) &&
(pi->srom_fem2g.extpagain == 3)) {
txgain =
- nphy_tpc_txgain_HiPwrEPA
- [txpi[core]];
+ nphy_tpc_txgain_HiPwrEPA
+ [txpi[core]];
} else {
- txgain =
- nphy_tpc_txgain_rev3[txpi
- [core]];
+ txgain = nphy_tpc_txgain_rev3
+ [txpi[core]];
}
}
}
@@ -27497,12 +28087,12 @@ void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1);
- if (NREV_GE(phyrev, 3)) {
+ if (NREV_GE(phyrev, 3))
mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
0xa5), (0x1 << 8), (0x1 << 8));
- } else {
+ else
mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14));
- }
+
write_phy_reg(pi, (core == PHY_CORE_0) ? 0xaa : 0xab, dac_gain);
wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16,
@@ -27562,9 +28152,8 @@ wlc_phy_txpwr_nphy_po_apply(u8 *srom_max, u8 pwr_offset,
{
u8 rate;
- for (rate = rate_start; rate <= rate_end; rate++) {
+ for (rate = rate_start; rate <= rate_end; rate++)
srom_max[rate] -= 2 * pwr_offset;
- }
}
void
@@ -27603,7 +28192,8 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
u16 pwr_offsets1[2], *pwr_offsets2 = NULL;
u8 *tx_srom_max_rate = NULL;
- for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP); band_num++) {
+ for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP);
+ band_num++) {
switch (band_num) {
case 0:
@@ -27619,7 +28209,7 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
pwr_offsets1[0] = (u16) (pi->ofdm2gpo & 0xffff);
pwr_offsets1[1] =
- (u16) (pi->ofdm2gpo >> 16) & 0xffff;
+ (u16) (pi->ofdm2gpo >> 16) & 0xffff;
pwr_offsets2 = pi->mcs2gpo;
@@ -27636,7 +28226,7 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
pwr_offsets1[0] = (u16) (pi->ofdm5gpo & 0xffff);
pwr_offsets1[1] =
- (u16) (pi->ofdm5gpo >> 16) & 0xffff;
+ (u16) (pi->ofdm5gpo >> 16) & 0xffff;
pwr_offsets2 = pi->mcs5gpo;
@@ -27653,7 +28243,7 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
pwr_offsets1[0] = (u16) (pi->ofdm5glpo & 0xffff);
pwr_offsets1[1] =
- (u16) (pi->ofdm5glpo >> 16) & 0xffff;
+ (u16) (pi->ofdm5glpo >> 16) & 0xffff;
pwr_offsets2 = pi->mcs5glpo;
@@ -27670,7 +28260,7 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
pwr_offsets1[0] = (u16) (pi->ofdm5ghpo & 0xffff);
pwr_offsets1[1] =
- (u16) (pi->ofdm5ghpo >> 16) & 0xffff;
+ (u16) (pi->ofdm5ghpo >> 16) & 0xffff;
pwr_offsets2 = pi->mcs5ghpo;
@@ -27696,12 +28286,10 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
TXP_FIRST_MCS_20_CDD,
TXP_LAST_MCS_20_CDD);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo,
TXP_FIRST_MCS_20_CDD,
TXP_LAST_MCS_20_CDD);
- }
wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate,
TXP_FIRST_OFDM_20_CDD,
@@ -27713,13 +28301,11 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
TXP_FIRST_MCS_20_STBC,
TXP_LAST_MCS_20_STBC);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate,
tmp_stbcpo,
TXP_FIRST_MCS_20_STBC,
TXP_LAST_MCS_20_STBC);
- }
wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate,
&pwr_offsets2[2], tmp_max_pwr,
@@ -27773,294 +28359,26 @@ void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi)
} else {
for (rate1 = TXP_FIRST_OFDM_40_SISO, rate2 =
- TXP_FIRST_OFDM; rate1 <= TXP_LAST_MCS_40_SDM;
+ TXP_FIRST_OFDM;
+ rate1 <= TXP_LAST_MCS_40_SDM;
rate1++, rate2++)
tx_srom_max_rate[rate1] =
- tx_srom_max_rate[rate2];
+ tx_srom_max_rate[rate2];
}
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate,
tmp_bw40po,
TXP_FIRST_OFDM_40_SISO,
TXP_LAST_MCS_40_SDM);
- }
tx_srom_max_rate[TXP_MCS_32] =
- tx_srom_max_rate[TXP_FIRST_MCS_40_CDD];
+ tx_srom_max_rate[TXP_FIRST_MCS_40_CDD];
}
return;
}
-static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
-{
- u16 bw40po, cddpo, stbcpo, bwduppo;
- uint band_num;
-
- if (pi->sh->sromrev >= 9) {
-
- return;
- }
-
- bw40po = (u16) PHY_GETINTVAR(pi, "bw40po");
- pi->bw402gpo = bw40po & 0xf;
- pi->bw405gpo = (bw40po & 0xf0) >> 4;
- pi->bw405glpo = (bw40po & 0xf00) >> 8;
- pi->bw405ghpo = (bw40po & 0xf000) >> 12;
-
- cddpo = (u16) PHY_GETINTVAR(pi, "cddpo");
- pi->cdd2gpo = cddpo & 0xf;
- pi->cdd5gpo = (cddpo & 0xf0) >> 4;
- pi->cdd5glpo = (cddpo & 0xf00) >> 8;
- pi->cdd5ghpo = (cddpo & 0xf000) >> 12;
-
- stbcpo = (u16) PHY_GETINTVAR(pi, "stbcpo");
- pi->stbc2gpo = stbcpo & 0xf;
- pi->stbc5gpo = (stbcpo & 0xf0) >> 4;
- pi->stbc5glpo = (stbcpo & 0xf00) >> 8;
- pi->stbc5ghpo = (stbcpo & 0xf000) >> 12;
-
- bwduppo = (u16) PHY_GETINTVAR(pi, "bwduppo");
- pi->bwdup2gpo = bwduppo & 0xf;
- pi->bwdup5gpo = (bwduppo & 0xf0) >> 4;
- pi->bwdup5glpo = (bwduppo & 0xf00) >> 8;
- pi->bwdup5ghpo = (bwduppo & 0xf000) >> 12;
-
- for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP); band_num++) {
- switch (band_num) {
- case 0:
-
- pi->nphy_txpid2g[PHY_CORE_0] =
- (u8) PHY_GETINTVAR(pi, "txpid2ga0");
- pi->nphy_txpid2g[PHY_CORE_1] =
- (u8) PHY_GETINTVAR(pi, "txpid2ga1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
- (s8) PHY_GETINTVAR(pi, "maxp2ga0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g =
- (s8) PHY_GETINTVAR(pi, "maxp2ga1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 =
- (s16) PHY_GETINTVAR(pi, "pa2gw0a0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 =
- (s16) PHY_GETINTVAR(pi, "pa2gw0a1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 =
- (s16) PHY_GETINTVAR(pi, "pa2gw1a0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 =
- (s16) PHY_GETINTVAR(pi, "pa2gw1a1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 =
- (s16) PHY_GETINTVAR(pi, "pa2gw2a0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 =
- (s16) PHY_GETINTVAR(pi, "pa2gw2a1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g =
- (s8) PHY_GETINTVAR(pi, "itt2ga0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g =
- (s8) PHY_GETINTVAR(pi, "itt2ga1");
-
- pi->cck2gpo = (u16) PHY_GETINTVAR(pi, "cck2gpo");
-
- pi->ofdm2gpo = (u32) PHY_GETINTVAR(pi, "ofdm2gpo");
-
- pi->mcs2gpo[0] = (u16) PHY_GETINTVAR(pi, "mcs2gpo0");
- pi->mcs2gpo[1] = (u16) PHY_GETINTVAR(pi, "mcs2gpo1");
- pi->mcs2gpo[2] = (u16) PHY_GETINTVAR(pi, "mcs2gpo2");
- pi->mcs2gpo[3] = (u16) PHY_GETINTVAR(pi, "mcs2gpo3");
- pi->mcs2gpo[4] = (u16) PHY_GETINTVAR(pi, "mcs2gpo4");
- pi->mcs2gpo[5] = (u16) PHY_GETINTVAR(pi, "mcs2gpo5");
- pi->mcs2gpo[6] = (u16) PHY_GETINTVAR(pi, "mcs2gpo6");
- pi->mcs2gpo[7] = (u16) PHY_GETINTVAR(pi, "mcs2gpo7");
- break;
- case 1:
-
- pi->nphy_txpid5g[PHY_CORE_0] =
- (u8) PHY_GETINTVAR(pi, "txpid5ga0");
- pi->nphy_txpid5g[PHY_CORE_1] =
- (u8) PHY_GETINTVAR(pi, "txpid5ga1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
- (s8) PHY_GETINTVAR(pi, "maxp5ga0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
- (s8) PHY_GETINTVAR(pi, "maxp5ga1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 =
- (s16) PHY_GETINTVAR(pi, "pa5gw0a0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 =
- (s16) PHY_GETINTVAR(pi, "pa5gw0a1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 =
- (s16) PHY_GETINTVAR(pi, "pa5gw1a0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 =
- (s16) PHY_GETINTVAR(pi, "pa5gw1a1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 =
- (s16) PHY_GETINTVAR(pi, "pa5gw2a0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 =
- (s16) PHY_GETINTVAR(pi, "pa5gw2a1");
- pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm =
- (s8) PHY_GETINTVAR(pi, "itt5ga0");
- pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm =
- (s8) PHY_GETINTVAR(pi, "itt5ga1");
-
- pi->ofdm5gpo = (u32) PHY_GETINTVAR(pi, "ofdm5gpo");
-
- pi->mcs5gpo[0] = (u16) PHY_GETINTVAR(pi, "mcs5gpo0");
- pi->mcs5gpo[1] = (u16) PHY_GETINTVAR(pi, "mcs5gpo1");
- pi->mcs5gpo[2] = (u16) PHY_GETINTVAR(pi, "mcs5gpo2");
- pi->mcs5gpo[3] = (u16) PHY_GETINTVAR(pi, "mcs5gpo3");
- pi->mcs5gpo[4] = (u16) PHY_GETINTVAR(pi, "mcs5gpo4");
- pi->mcs5gpo[5] = (u16) PHY_GETINTVAR(pi, "mcs5gpo5");
- pi->mcs5gpo[6] = (u16) PHY_GETINTVAR(pi, "mcs5gpo6");
- pi->mcs5gpo[7] = (u16) PHY_GETINTVAR(pi, "mcs5gpo7");
- break;
- case 2:
-
- pi->nphy_txpid5gl[0] =
- (u8) PHY_GETINTVAR(pi, "txpid5gla0");
- pi->nphy_txpid5gl[1] =
- (u8) PHY_GETINTVAR(pi, "txpid5gla1");
- pi->nphy_pwrctrl_info[0].max_pwr_5gl =
- (s8) PHY_GETINTVAR(pi, "maxp5gla0");
- pi->nphy_pwrctrl_info[1].max_pwr_5gl =
- (s8) PHY_GETINTVAR(pi, "maxp5gla1");
- pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 =
- (s16) PHY_GETINTVAR(pi, "pa5glw0a0");
- pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 =
- (s16) PHY_GETINTVAR(pi, "pa5glw0a1");
- pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 =
- (s16) PHY_GETINTVAR(pi, "pa5glw1a0");
- pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 =
- (s16) PHY_GETINTVAR(pi, "pa5glw1a1");
- pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 =
- (s16) PHY_GETINTVAR(pi, "pa5glw2a0");
- pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 =
- (s16) PHY_GETINTVAR(pi, "pa5glw2a1");
- pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0;
- pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0;
-
- pi->ofdm5glpo = (u32) PHY_GETINTVAR(pi, "ofdm5glpo");
-
- pi->mcs5glpo[0] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo0");
- pi->mcs5glpo[1] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo1");
- pi->mcs5glpo[2] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo2");
- pi->mcs5glpo[3] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo3");
- pi->mcs5glpo[4] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo4");
- pi->mcs5glpo[5] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo5");
- pi->mcs5glpo[6] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo6");
- pi->mcs5glpo[7] =
- (u16) PHY_GETINTVAR(pi, "mcs5glpo7");
- break;
- case 3:
-
- pi->nphy_txpid5gh[0] =
- (u8) PHY_GETINTVAR(pi, "txpid5gha0");
- pi->nphy_txpid5gh[1] =
- (u8) PHY_GETINTVAR(pi, "txpid5gha1");
- pi->nphy_pwrctrl_info[0].max_pwr_5gh =
- (s8) PHY_GETINTVAR(pi, "maxp5gha0");
- pi->nphy_pwrctrl_info[1].max_pwr_5gh =
- (s8) PHY_GETINTVAR(pi, "maxp5gha1");
- pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 =
- (s16) PHY_GETINTVAR(pi, "pa5ghw0a0");
- pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 =
- (s16) PHY_GETINTVAR(pi, "pa5ghw0a1");
- pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 =
- (s16) PHY_GETINTVAR(pi, "pa5ghw1a0");
- pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 =
- (s16) PHY_GETINTVAR(pi, "pa5ghw1a1");
- pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 =
- (s16) PHY_GETINTVAR(pi, "pa5ghw2a0");
- pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 =
- (s16) PHY_GETINTVAR(pi, "pa5ghw2a1");
- pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0;
- pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0;
-
- pi->ofdm5ghpo = (u32) PHY_GETINTVAR(pi, "ofdm5ghpo");
-
- pi->mcs5ghpo[0] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo0");
- pi->mcs5ghpo[1] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo1");
- pi->mcs5ghpo[2] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo2");
- pi->mcs5ghpo[3] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo3");
- pi->mcs5ghpo[4] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo4");
- pi->mcs5ghpo[5] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo5");
- pi->mcs5ghpo[6] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo6");
- pi->mcs5ghpo[7] =
- (u16) PHY_GETINTVAR(pi, "mcs5ghpo7");
- break;
- }
- }
-
- wlc_phy_txpwr_apply_nphy(pi);
-}
-
-static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
-{
-
- pi->antswitch = (u8) PHY_GETINTVAR(pi, "antswitch");
- pi->aa2g = (u8) PHY_GETINTVAR(pi, "aa2g");
- pi->aa5g = (u8) PHY_GETINTVAR(pi, "aa5g");
-
- pi->srom_fem2g.tssipos = (u8) PHY_GETINTVAR(pi, "tssipos2g");
- pi->srom_fem2g.extpagain = (u8) PHY_GETINTVAR(pi, "extpagain2g");
- pi->srom_fem2g.pdetrange = (u8) PHY_GETINTVAR(pi, "pdetrange2g");
- pi->srom_fem2g.triso = (u8) PHY_GETINTVAR(pi, "triso2g");
- pi->srom_fem2g.antswctrllut = (u8) PHY_GETINTVAR(pi, "antswctl2g");
-
- pi->srom_fem5g.tssipos = (u8) PHY_GETINTVAR(pi, "tssipos5g");
- pi->srom_fem5g.extpagain = (u8) PHY_GETINTVAR(pi, "extpagain5g");
- pi->srom_fem5g.pdetrange = (u8) PHY_GETINTVAR(pi, "pdetrange5g");
- pi->srom_fem5g.triso = (u8) PHY_GETINTVAR(pi, "triso5g");
- if (PHY_GETVAR(pi, "antswctl5g")) {
-
- pi->srom_fem5g.antswctrllut =
- (u8) PHY_GETINTVAR(pi, "antswctl5g");
- } else {
-
- pi->srom_fem5g.antswctrllut =
- (u8) PHY_GETINTVAR(pi, "antswctl2g");
- }
-
- wlc_phy_txpower_ipa_upd(pi);
-
- pi->phy_txcore_disable_temp = (s16) PHY_GETINTVAR(pi, "tempthresh");
- if (pi->phy_txcore_disable_temp == 0) {
- pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
- }
-
- pi->phy_tempsense_offset = (s8) PHY_GETINTVAR(pi, "tempoffset");
- if (pi->phy_tempsense_offset != 0) {
- if (pi->phy_tempsense_offset >
- (NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET)) {
- pi->phy_tempsense_offset = NPHY_SROM_MAXTEMPOFFSET;
- } else if (pi->phy_tempsense_offset < (NPHY_SROM_TEMPSHIFT +
- NPHY_SROM_MINTEMPOFFSET)) {
- pi->phy_tempsense_offset = NPHY_SROM_MINTEMPOFFSET;
- } else {
- pi->phy_tempsense_offset -= NPHY_SROM_TEMPSHIFT;
- }
- }
-
- pi->phy_txcore_enable_temp =
- pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP;
-
- pi->phycal_tempdelta = (u8) PHY_GETINTVAR(pi, "phycal_tempdelta");
- if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA) {
- pi->phycal_tempdelta = 0;
- }
-
- wlc_phy_txpwr_srom_read_ppr_nphy(pi);
-
- return true;
-}
-
void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi)
{
u8 tx_pwr_ctrl_state;
@@ -28081,512 +28399,10 @@ void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi)
wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
}
-static void wlc_phy_txpwrctrl_coeff_setup_nphy(struct brcms_phy *pi)
-{
- u32 idx;
- u16 iqloCalbuf[7];
- u32 iqcomp, locomp, curr_locomp;
- s8 locomp_i, locomp_q;
- s8 curr_locomp_i, curr_locomp_q;
- u32 tbl_id, tbl_len, tbl_offset;
- u32 regval[128];
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- wlc_phy_table_read_nphy(pi, 15, 7, 80, 16, iqloCalbuf);
-
- tbl_len = 128;
- tbl_offset = 320;
- for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
- tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
- iqcomp =
- (tbl_id ==
- 26) ? (((u32) (iqloCalbuf[0] & 0x3ff)) << 10) |
- (iqloCalbuf[1] & 0x3ff)
- : (((u32) (iqloCalbuf[2] & 0x3ff)) << 10) |
- (iqloCalbuf[3] & 0x3ff);
-
- for (idx = 0; idx < tbl_len; idx++) {
- regval[idx] = iqcomp;
- }
- wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
- regval);
- }
-
- tbl_offset = 448;
- for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
- tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
-
- locomp =
- (u32) ((tbl_id == 26) ? iqloCalbuf[5] : iqloCalbuf[6]);
- locomp_i = (s8) ((locomp >> 8) & 0xff);
- locomp_q = (s8) ((locomp) & 0xff);
- for (idx = 0; idx < tbl_len; idx++) {
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- curr_locomp_i = locomp_i;
- curr_locomp_q = locomp_q;
- } else {
- curr_locomp_i = (s8) ((locomp_i *
- nphy_tpc_loscale[idx] +
- 128) >> 8);
- curr_locomp_q =
- (s8) ((locomp_q * nphy_tpc_loscale[idx] +
- 128) >> 8);
- }
- curr_locomp = (u32) ((curr_locomp_i & 0xff) << 8);
- curr_locomp |= (u32) (curr_locomp_q & 0xff);
- regval[idx] = curr_locomp;
- }
- wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
- regval);
- }
-
- if (NREV_LT(pi->pubpi.phy_rev, 2)) {
-
- wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX1, 0xFFFF);
- wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX2, 0xFFFF);
- }
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-}
-
-static void wlc_phy_ipa_internal_tssi_setup_nphy(struct brcms_phy *pi)
-{
- u8 core;
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TX_SSI_MASTER, 0x5);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TX_SSI_MUX, 0xe);
-
- if (pi->pubpi.radiorev != 5)
- WRITE_RADIO_REG3(pi, RADIO_2057, TX,
- core, TSSIA, 0);
-
- if (!NREV_IS(pi->pubpi.phy_rev, 7)) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX,
- core, TSSIG, 0x1);
- } else {
-
- WRITE_RADIO_REG3(pi, RADIO_2057, TX,
- core, TSSIG, 0x31);
- }
- } else {
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TX_SSI_MASTER, 0x9);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TX_SSI_MUX, 0xc);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core,
- TSSIG, 0);
-
- if (pi->pubpi.radiorev != 5) {
- if (!NREV_IS(pi->pubpi.phy_rev, 7)) {
-
- WRITE_RADIO_REG3(pi, RADIO_2057,
- TX, core,
- TSSIA, 0x1);
- } else {
-
- WRITE_RADIO_REG3(pi, RADIO_2057,
- TX, core,
- TSSIA, 0x31);
- }
- }
- }
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG,
- 0);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC,
- 0);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM,
- 0x3);
- WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1,
- 0x0);
- }
- } else {
- WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR31,
- (CHSPEC_IS2G(pi->radio_chanspec)) ? 0x128 :
- 0x80);
- WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR30, 0x0);
- WRITE_RADIO_SYN(pi, RADIO_2056, GPIO_MASTER1, 0x29);
-
- for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_VCM_HG,
- 0x0);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_IDAC,
- 0x0);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_VCM,
- 0x3);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TX_AMP_DET,
- 0x0);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC1,
- 0x8);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC2,
- 0x0);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC3,
- 0x0);
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- TX_SSI_MASTER, 0x5);
-
- if (pi->pubpi.radiorev != 5)
- WRITE_RADIO_REG2(pi, RADIO_2056, TX,
- core, TSSIA, 0x0);
- if (NREV_GE(pi->pubpi.phy_rev, 5)) {
-
- WRITE_RADIO_REG2(pi, RADIO_2056, TX,
- core, TSSIG, 0x31);
- } else {
- WRITE_RADIO_REG2(pi, RADIO_2056, TX,
- core, TSSIG, 0x11);
- }
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- TX_SSI_MUX, 0xe);
- } else {
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- TX_SSI_MASTER, 0x9);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- TSSIA, 0x31);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- TSSIG, 0x0);
- WRITE_RADIO_REG2(pi, RADIO_2056, TX, core,
- TX_SSI_MUX, 0xc);
- }
- }
- }
-}
-
-static void wlc_phy_txpwrctrl_idle_tssi_nphy(struct brcms_phy *pi)
-{
- s32 rssi_buf[4];
- s32 int_val;
-
- if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) || PHY_MUTED(pi))
-
- return;
-
- if (PHY_IPA(pi)) {
- wlc_phy_ipa_internal_tssi_setup_nphy(pi);
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
- 0, 0x3, 0,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 0);
- }
-
- wlc_phy_stopplayback_nphy(pi);
-
- wlc_phy_tx_tone_nphy(pi, 4000, 0, 0, 0, false);
-
- udelay(20);
- int_val =
- wlc_phy_poll_rssi_nphy(pi, (u8) NPHY_RSSI_SEL_TSSI_2G, rssi_buf,
- 1);
- wlc_phy_stopplayback_nphy(pi);
- wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, 0);
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12),
- 0, 0x3, 1,
- NPHY_REV7_RFCTRLOVERRIDE_ID0);
- } else if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 1);
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
- pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g =
- (u8) ((int_val >> 24) & 0xff);
- pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g =
- (u8) ((int_val >> 24) & 0xff);
-
- pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g =
- (u8) ((int_val >> 8) & 0xff);
- pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g =
- (u8) ((int_val >> 8) & 0xff);
- } else {
- pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g =
- (u8) ((int_val >> 24) & 0xff);
-
- pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g =
- (u8) ((int_val >> 8) & 0xff);
-
- pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g =
- (u8) ((int_val >> 16) & 0xff);
- pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g =
- (u8) ((int_val) & 0xff);
- }
-
-}
-
-static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi)
-{
- u32 idx;
- s16 a1[2], b0[2], b1[2];
- s8 target_pwr_qtrdbm[2];
- s32 num, den, pwr_est;
- u8 chan_freq_range;
- u8 idle_tssi[2];
- u32 tbl_id, tbl_len, tbl_offset;
- u32 regval[64];
- u8 core;
-
- if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
- wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
- (void)R_REG(&pi->regs->maccontrol);
- udelay(1);
- }
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, true);
-
- or_phy_reg(pi, 0x122, (0x1 << 0));
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- and_phy_reg(pi, 0x1e7, (u16) (~(0x1 << 15)));
- } else {
-
- or_phy_reg(pi, 0x1e7, (0x1 << 15));
- }
-
- if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
- wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
-
- if (pi->sh->sromrev < 4) {
- idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
- idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
- target_pwr_qtrdbm[0] = 13 * 4;
- target_pwr_qtrdbm[1] = 13 * 4;
- a1[0] = -424;
- a1[1] = -424;
- b0[0] = 5612;
- b0[1] = 5612;
- b1[1] = -1393;
- b1[0] = -1393;
- } else {
-
- chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
- switch (chan_freq_range) {
- case WL_CHAN_FREQ_RANGE_2G:
- idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
- idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_2g;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_2g;
- a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1;
- a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1;
- b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0;
- b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b0;
- b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b1;
- b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b1;
- break;
- case WL_CHAN_FREQ_RANGE_5GL:
- idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
- idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_5gl;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_5gl;
- a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1;
- a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1;
- b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0;
- b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0;
- b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1;
- b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1;
- break;
- case WL_CHAN_FREQ_RANGE_5GM:
- idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
- idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_5gm;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_5gm;
- a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1;
- a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1;
- b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0;
- b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b0;
- b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b1;
- b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b1;
- break;
- case WL_CHAN_FREQ_RANGE_5GH:
- idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g;
- idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g;
- target_pwr_qtrdbm[0] =
- pi->nphy_pwrctrl_info[0].max_pwr_5gh;
- target_pwr_qtrdbm[1] =
- pi->nphy_pwrctrl_info[1].max_pwr_5gh;
- a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1;
- a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1;
- b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0;
- b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0;
- b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1;
- b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1;
- break;
- default:
- idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g;
- idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g;
- target_pwr_qtrdbm[0] = 13 * 4;
- target_pwr_qtrdbm[1] = 13 * 4;
- a1[0] = -424;
- a1[1] = -424;
- b0[0] = 5612;
- b0[1] = 5612;
- b1[1] = -1393;
- b1[0] = -1393;
- break;
- }
- }
-
- target_pwr_qtrdbm[0] = (s8) pi->tx_power_max;
- target_pwr_qtrdbm[1] = (s8) pi->tx_power_max;
-
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- if (pi->srom_fem2g.tssipos) {
- or_phy_reg(pi, 0x1e9, (0x1 << 14));
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- for (core = 0; core <= 1; core++) {
- if (PHY_IPA(pi)) {
-
- if (CHSPEC_IS2G(pi->radio_chanspec)) {
- WRITE_RADIO_REG3(pi, RADIO_2057,
- TX, core,
- TX_SSI_MUX,
- 0xe);
- } else {
- WRITE_RADIO_REG3(pi, RADIO_2057,
- TX, core,
- TX_SSI_MUX,
- 0xc);
- }
- } else {
- }
- }
- } else {
- if (PHY_IPA(pi)) {
-
- write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
- RADIO_2056_TX0,
- (CHSPEC_IS5G
- (pi->
- radio_chanspec)) ? 0xc : 0xe);
- write_radio_reg(pi,
- RADIO_2056_TX_TX_SSI_MUX |
- RADIO_2056_TX1,
- (CHSPEC_IS5G
- (pi->
- radio_chanspec)) ? 0xc : 0xe);
- } else {
-
- write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
- RADIO_2056_TX0, 0x11);
- write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX |
- RADIO_2056_TX1, 0x11);
- }
- }
- }
-
- if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) {
- wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK);
- (void)R_REG(&pi->regs->maccontrol);
- udelay(1);
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- mod_phy_reg(pi, 0x1e7, (0x7f << 0),
- (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0));
- } else {
- mod_phy_reg(pi, 0x1e7, (0x7f << 0),
- (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0));
- }
-
- if (NREV_GE(pi->pubpi.phy_rev, 7)) {
- mod_phy_reg(pi, 0x222, (0xff << 0),
- (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0));
- } else if (NREV_GT(pi->pubpi.phy_rev, 1)) {
- mod_phy_reg(pi, 0x222, (0xff << 0),
- (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0));
- }
-
- if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12))
- wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0);
-
- write_phy_reg(pi, 0x1e8, (0x3 << 8) | (240 << 0));
-
- write_phy_reg(pi, 0x1e9,
- (1 << 15) | (idle_tssi[0] << 0) | (idle_tssi[1] << 8));
-
- write_phy_reg(pi, 0x1ea,
- (target_pwr_qtrdbm[0] << 0) |
- (target_pwr_qtrdbm[1] << 8));
-
- tbl_len = 64;
- tbl_offset = 0;
- for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL;
- tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) {
-
- for (idx = 0; idx < tbl_len; idx++) {
- num =
- 8 * (16 * b0[tbl_id - 26] + b1[tbl_id - 26] * idx);
- den = 32768 + a1[tbl_id - 26] * idx;
- pwr_est = max(((4 * num + den / 2) / den), -8);
- if (NREV_LT(pi->pubpi.phy_rev, 3)) {
- if (idx <=
- (uint) (31 - idle_tssi[tbl_id - 26] + 1))
- pwr_est =
- max(pwr_est,
- target_pwr_qtrdbm[tbl_id - 26] +
- 1);
- }
- regval[idx] = (u32) pwr_est;
- }
- wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32,
- regval);
- }
-
- wlc_phy_txpwr_limit_to_tbl_nphy(pi);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, 8,
- pi->adj_pwr_tbl_nphy);
- wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, 8,
- pi->adj_pwr_tbl_nphy);
-
- if (pi->phyhang_avoid)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
-}
-
static bool wlc_phy_txpwr_ison_nphy(struct brcms_phy *pi)
{
return read_phy_reg((pi), 0x1e7) & ((0x1 << 15) |
- (0x1 << 14) | (0x1 << 13));
-}
-
-static u8 wlc_phy_txpwr_idx_cur_get_nphy(struct brcms_phy *pi, u8 core)
-{
- u16 tmp;
- tmp = read_phy_reg(pi, ((core == PHY_CORE_0) ? 0x1ed : 0x1ee));
-
- tmp = (tmp & (0x7f << 8)) >> 8;
- return (u8) tmp;
-}
-
-static void
-wlc_phy_txpwr_idx_cur_set_nphy(struct brcms_phy *pi, u8 idx0, u8 idx1)
-{
- mod_phy_reg(pi, 0x1e7, (0x7f << 0), idx0);
-
- if (NREV_GT(pi->pubpi.phy_rev, 1))
- mod_phy_reg(pi, 0x222, (0xff << 0), idx1);
+ (0x1 << 14) | (0x1 << 13));
}
u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi)
@@ -28600,12 +28416,9 @@ u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi)
tmp = (pwr_idx[0] << 8) | pwr_idx[1];
} else {
- tmp =
- ((pi->nphy_txpwrindex[PHY_CORE_0].
- index_internal & 0xff) << 8) | (pi->
- nphy_txpwrindex
- [PHY_CORE_1].
- index_internal & 0xff);
+ tmp = ((pi->nphy_txpwrindex[PHY_CORE_0].index_internal & 0xff)
+ << 8) |
+ (pi->nphy_txpwrindex[PHY_CORE_1].index_internal & 0xff);
}
return tmp;
@@ -28618,13 +28431,12 @@ void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi)
|| (wlc_phy_txpwr_ison_nphy(pi)
&&
(((u32)
- ABS(wlc_phy_txpwr_idx_cur_get_nphy(pi, 0) -
+ abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 0) -
pi->nphy_papd_tx_gain_at_last_cal[0]) >= 4)
|| ((u32)
- ABS(wlc_phy_txpwr_idx_cur_get_nphy(pi, 1) -
- pi->nphy_papd_tx_gain_at_last_cal[1]) >= 4))))) {
+ abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 1) -
+ pi->nphy_papd_tx_gain_at_last_cal[1]) >= 4)))))
wlc_phy_a4(pi, true);
- }
}
void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
@@ -28655,32 +28467,29 @@ void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
for (core = 0; core < pi->pubpi.phy_corenum;
core++)
pi->nphy_txpwr_idx[core] =
- wlc_phy_txpwr_idx_cur_get_nphy(pi,
- (u8)
- core);
+ wlc_phy_txpwr_idx_cur_get_nphy(
+ pi,
+ (u8) core);
}
}
tbl_len = 84;
tbl_offset = 64;
- for (ctr = 0; ctr < tbl_len; ctr++) {
+ for (ctr = 0; ctr < tbl_len; ctr++)
regval[ctr] = 0;
- }
wlc_phy_table_write_nphy(pi, 26, tbl_len, tbl_offset, 16,
regval);
wlc_phy_table_write_nphy(pi, 27, tbl_len, tbl_offset, 16,
regval);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
-
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
and_phy_reg(pi, 0x1e7,
(u16) (~((0x1 << 15) |
- (0x1 << 14) | (0x1 << 13))));
- } else {
+ (0x1 << 14) | (0x1 << 13))));
+ else
and_phy_reg(pi, 0x1e7,
(u16) (~((0x1 << 14) | (0x1 << 13))));
- }
if (NREV_GE(pi->pubpi.phy_rev, 3)) {
or_phy_reg(pi, 0x8f, (0x1 << 8));
@@ -28694,7 +28503,8 @@ void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
else if (NREV_LT(pi->pubpi.phy_rev, 2))
mod_phy_reg(pi, 0xdc, 0x00ff, 0x5a);
- if (NREV_LT(pi->pubpi.phy_rev, 2) && IS40MHZ(pi))
+ if (NREV_LT(pi->pubpi.phy_rev, 2) &&
+ pi->bw == WL_CHANSPEC_BW_40)
wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR,
MHF1_IQSWAP_WAR, BRCM_BAND_ALL);
@@ -28730,7 +28540,7 @@ void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
if (NREV_GE(pi->pubpi.phy_rev, 3)) {
if ((pi->nphy_txpwr_idx[0] != 128)
- && (pi->nphy_txpwr_idx[1] != 128)) {
+ && (pi->nphy_txpwr_idx[1] != 128))
wlc_phy_txpwr_idx_cur_set_nphy(pi,
pi->
nphy_txpwr_idx
@@ -28738,7 +28548,6 @@ void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
pi->
nphy_txpwr_idx
[1]);
- }
}
if (NREV_GE(pi->pubpi.phy_rev, 3)) {
@@ -28753,7 +28562,8 @@ void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type)
else if (NREV_LT(pi->pubpi.phy_rev, 2))
mod_phy_reg(pi, 0xdc, 0x00ff, 0x40);
- if (NREV_LT(pi->pubpi.phy_rev, 2) && IS40MHZ(pi))
+ if (NREV_LT(pi->pubpi.phy_rev, 2) &&
+ pi->bw == WL_CHANSPEC_BW_40)
wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR,
0x0, BRCM_BAND_ALL);
@@ -28799,17 +28609,14 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
for (core = 0; core < pi->pubpi.phy_corenum; core++) {
- if ((core_mask & (1 << core)) == 0) {
+ if ((core_mask & (1 << core)) == 0)
continue;
- }
txpwrctl_tbl = (core == PHY_CORE_0) ? 26 : 27;
if (txpwrindex < 0) {
- if (pi->nphy_txpwrindex[core].index < 0) {
-
+ if (pi->nphy_txpwrindex[core].index < 0)
continue;
- }
if (NREV_GE(pi->pubpi.phy_rev, 3)) {
mod_phy_reg(pi, 0x8f,
@@ -28842,29 +28649,21 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2);
if (restore_cals) {
-
- wlc_phy_table_write_nphy(pi, 15, 2,
- (80 + 2 * core), 16,
- (void *)&pi->
- nphy_txpwrindex[core].
- iqcomp_a);
-
- wlc_phy_table_write_nphy(pi, 15, 1, (85 + core),
- 16,
- &pi->
- nphy_txpwrindex[core].
- locomp);
- wlc_phy_table_write_nphy(pi, 15, 1, (93 + core),
- 16,
- (void *)&pi->
- nphy_txpwrindex[core].
- locomp);
+ wlc_phy_table_write_nphy(
+ pi, 15, 2, (80 + 2 * core), 16,
+ &pi->nphy_txpwrindex[core].iqcomp_a);
+ wlc_phy_table_write_nphy(
+ pi, 15, 1, (85 + core), 16,
+ &pi->nphy_txpwrindex[core].locomp);
+ wlc_phy_table_write_nphy(
+ pi, 15, 1, (93 + core), 16,
+ &pi->nphy_txpwrindex[core].locomp);
}
wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl);
pi->nphy_txpwrindex[core].index_internal =
- pi->nphy_txpwrindex[core].index_internal_save;
+ pi->nphy_txpwrindex[core].index_internal_save;
} else {
if (pi->nphy_txpwrindex[core].index < 0) {
@@ -28879,14 +28678,13 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
AfectrlOverride);
} else {
pi->nphy_txpwrindex[core].
- AfectrlOverride =
- read_phy_reg(pi, 0xa5);
+ AfectrlOverride =
+ read_phy_reg(pi, 0xa5);
}
pi->nphy_txpwrindex[core].AfeCtrlDacGain =
- read_phy_reg(pi,
- (core ==
- PHY_CORE_0) ? 0xaa : 0xab);
+ read_phy_reg(pi, (core == PHY_CORE_0) ?
+ 0xaa : 0xab);
wlc_phy_table_read_nphy(pi, 7, 1,
(0x110 + core), 16,
@@ -28898,23 +28696,23 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
&tmpval);
tmpval >>= ((core == PHY_CORE_0) ? 8 : 0);
tmpval &= 0xff;
- pi->nphy_txpwrindex[core].bbmult =
- (u8) tmpval;
+ pi->nphy_txpwrindex[core].bbmult = (u8) tmpval;
wlc_phy_table_read_nphy(pi, 15, 2,
(80 + 2 * core), 16,
- (void *)&pi->
+ &pi->
nphy_txpwrindex[core].
iqcomp_a);
wlc_phy_table_read_nphy(pi, 15, 1, (85 + core),
16,
- (void *)&pi->
+ &pi->
nphy_txpwrindex[core].
locomp);
pi->nphy_txpwrindex[core].index_internal_save =
- pi->nphy_txpwrindex[core].index_internal;
+ pi->nphy_txpwrindex[core].
+ index_internal;
}
tx_pwr_ctrl_state = pi->nphy_txpwrctrl;
@@ -28927,22 +28725,22 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
(tx_ind0 + txpwrindex), 32,
&txgain);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
- rad_gain =
- (txgain >> 16) & ((1 << (32 - 16 + 1)) - 1);
- } else {
- rad_gain =
- (txgain >> 16) & ((1 << (28 - 16 + 1)) - 1);
- }
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
+ rad_gain = (txgain >> 16) &
+ ((1 << (32 - 16 + 1)) - 1);
+ else
+ rad_gain = (txgain >> 16) &
+ ((1 << (28 - 16 + 1)) - 1);
+
dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1);
bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1);
- if (NREV_GE(pi->pubpi.phy_rev, 3)) {
+ if (NREV_GE(pi->pubpi.phy_rev, 3))
mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f :
0xa5), (0x1 << 8), (0x1 << 8));
- } else {
+ else
mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14));
- }
+
write_phy_reg(pi, (core == PHY_CORE_0) ?
0xaa : 0xab, dac_gain);
@@ -28951,9 +28749,8 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2);
m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00);
- m1m2 |=
- ((core ==
- PHY_CORE_0) ? (bbmult << 8) : (bbmult << 0));
+ m1m2 |= ((core == PHY_CORE_0) ?
+ (bbmult << 8) : (bbmult << 0));
wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2);
@@ -28974,23 +28771,20 @@ wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex,
wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1,
(lo_ind0 + txpwrindex), 32,
&locomp);
- if (restore_cals) {
+ if (restore_cals)
wlc_phy_table_write_nphy(pi, 15, 1, (85 + core),
16, &locomp);
- }
if (NREV_IS(pi->pubpi.phy_rev, 1))
wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF);
if (PHY_IPA(pi)) {
wlc_phy_table_read_nphy(pi,
- (core ==
- PHY_CORE_0 ?
- NPHY_TBL_ID_CORE1TXPWRCTL
- :
- NPHY_TBL_ID_CORE2TXPWRCTL),
- 1, 576 + txpwrindex, 32,
- &rfpwr_offset);
+ (core == PHY_CORE_0 ?
+ NPHY_TBL_ID_CORE1TXPWRCTL :
+ NPHY_TBL_ID_CORE2TXPWRCTL),
+ 1, 576 + txpwrindex, 32,
+ &rfpwr_offset);
mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 :
0x29b, (0x1ff << 4),
@@ -29046,7 +28840,7 @@ void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable)
if (enable) {
if (pi->nphy_deaf_count == 0) {
pi->classifier_state =
- wlc_phy_classifier_nphy(pi, 0, 0);
+ wlc_phy_classifier_nphy(pi, 0, 0);
wlc_phy_classifier_nphy(pi, (0x7 << 0), 4);
wlc_phy_clip_det_nphy(pi, 0, pi->clip_state);
wlc_phy_clip_det_nphy(pi, 1, clip_off);
@@ -29074,9 +28868,9 @@ void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode)
if (mode) {
if (pi->nphy_deaf_count == 0)
wlc_phy_stay_in_carriersearch_nphy(pi, true);
- } else {
- if (pi->nphy_deaf_count > 0)
- wlc_phy_stay_in_carriersearch_nphy(pi, false);
+ } else if (pi->nphy_deaf_count > 0) {
+ wlc_phy_stay_in_carriersearch_nphy(pi, false);
}
+
wlapi_enable_mac(pi->sh->physhim);
}
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/staging/brcm80211/brcmsmac/phy/phy_qmath.c
index 01ff0c8eb4b9..faf1ebe76068 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phy_qmath.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phy_qmath.c
@@ -17,89 +17,95 @@
#include "phy_qmath.h"
/*
-Description: This function make 16 bit unsigned multiplication. To fit the output into
-16 bits the 32 bit multiplication result is right shifted by 16 bits.
-*/
+ * Description: This function make 16 bit unsigned multiplication.
+ * To fit the output into 16 bits the 32 bit multiplication result is right
+ * shifted by 16 bits.
+ */
u16 qm_mulu16(u16 op1, u16 op2)
{
return (u16) (((u32) op1 * (u32) op2) >> 16);
}
/*
-Description: This function make 16 bit multiplication and return the result in 16 bits.
-To fit the multiplication result into 16 bits the multiplication result is right shifted by
-15 bits. Right shifting 15 bits instead of 16 bits is done to remove the extra sign bit formed
-due to the multiplication.
-When both the 16bit inputs are 0x8000 then the output is saturated to 0x7fffffff.
-*/
+ * Description: This function make 16 bit multiplication and return the result
+ * in 16 bits. To fit the multiplication result into 16 bits the multiplication
+ * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits
+ * is done to remove the extra sign bit formed due to the multiplication.
+ * When both the 16bit inputs are 0x8000 then the output is saturated to
+ * 0x7fffffff.
+ */
s16 qm_muls16(s16 op1, s16 op2)
{
s32 result;
- if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000) {
+ if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000)
result = 0x7fffffff;
- } else {
+ else
result = ((s32) (op1) * (s32) (op2));
- }
+
return (s16) (result >> 15);
}
/*
-Description: This function add two 32 bit numbers and return the 32bit result.
-If the result overflow 32 bits, the output will be saturated to 32bits.
-*/
+ * Description: This function add two 32 bit numbers and return the 32bit
+ * result. If the result overflow 32 bits, the output will be saturated to
+ * 32bits.
+ */
s32 qm_add32(s32 op1, s32 op2)
{
s32 result;
result = op1 + op2;
- if (op1 < 0 && op2 < 0 && result > 0) {
+ if (op1 < 0 && op2 < 0 && result > 0)
result = 0x80000000;
- } else if (op1 > 0 && op2 > 0 && result < 0) {
+ else if (op1 > 0 && op2 > 0 && result < 0)
result = 0x7fffffff;
- }
+
return result;
}
/*
-Description: This function add two 16 bit numbers and return the 16bit result.
-If the result overflow 16 bits, the output will be saturated to 16bits.
-*/
+ * Description: This function add two 16 bit numbers and return the 16bit
+ * result. If the result overflow 16 bits, the output will be saturated to
+ * 16bits.
+ */
s16 qm_add16(s16 op1, s16 op2)
{
s16 result;
s32 temp = (s32) op1 + (s32) op2;
- if (temp > (s32) 0x7fff) {
+ if (temp > (s32) 0x7fff)
result = (s16) 0x7fff;
- } else if (temp < (s32) 0xffff8000) {
+ else if (temp < (s32) 0xffff8000)
result = (s16) 0xffff8000;
- } else {
+ else
result = (s16) temp;
- }
+
return result;
}
/*
-Description: This function make 16 bit subtraction and return the 16bit result.
-If the result overflow 16 bits, the output will be saturated to 16bits.
-*/
+ * Description: This function make 16 bit subtraction and return the 16bit
+ * result. If the result overflow 16 bits, the output will be saturated to
+ * 16bits.
+ */
s16 qm_sub16(s16 op1, s16 op2)
{
s16 result;
s32 temp = (s32) op1 - (s32) op2;
- if (temp > (s32) 0x7fff) {
+ if (temp > (s32) 0x7fff)
result = (s16) 0x7fff;
- } else if (temp < (s32) 0xffff8000) {
+ else if (temp < (s32) 0xffff8000)
result = (s16) 0xffff8000;
- } else {
+ else
result = (s16) temp;
- }
+
return result;
}
/*
-Description: This function make a 32 bit saturated left shift when the specified shift
-is +ve. This function will make a 32 bit right shift when the specified shift is -ve.
-This function return the result after shifting operation.
-*/
+ * Description: This function make a 32 bit saturated left shift when the
+ * specified shift is +ve. This function will make a 32 bit right shift when
+ * the specified shift is -ve. This function return the result after shifting
+ * operation.
+ */
s32 qm_shl32(s32 op, int shift)
{
int i;
@@ -110,20 +116,21 @@ s32 qm_shl32(s32 op, int shift)
else if (shift < -31)
shift = -31;
if (shift >= 0) {
- for (i = 0; i < shift; i++) {
+ for (i = 0; i < shift; i++)
result = qm_add32(result, result);
- }
} else {
result = result >> (-shift);
}
+
return result;
}
/*
-Description: This function make a 16 bit saturated left shift when the specified shift
-is +ve. This function will make a 16 bit right shift when the specified shift is -ve.
-This function return the result after shifting operation.
-*/
+ * Description: This function make a 16 bit saturated left shift when the
+ * specified shift is +ve. This function will make a 16 bit right shift when
+ * the specified shift is -ve. This function return the result after shifting
+ * operation.
+ */
s16 qm_shl16(s16 op, int shift)
{
int i;
@@ -134,29 +141,29 @@ s16 qm_shl16(s16 op, int shift)
else if (shift < -15)
shift = -15;
if (shift > 0) {
- for (i = 0; i < shift; i++) {
+ for (i = 0; i < shift; i++)
result = qm_add16(result, result);
- }
} else {
result = result >> (-shift);
}
+
return result;
}
/*
-Description: This function make a 16 bit right shift when shift is +ve.
-This function make a 16 bit saturated left shift when shift is -ve. This function
-return the result of the shift operation.
-*/
+ * Description: This function make a 16 bit right shift when shift is +ve.
+ * This function make a 16 bit saturated left shift when shift is -ve. This
+ * function return the result of the shift operation.
+ */
s16 qm_shr16(s16 op, int shift)
{
return qm_shl16(op, -shift);
}
/*
-Description: This function return the number of redundant sign bits in a 32 bit number.
-Example: qm_norm32(0x00000080) = 23
-*/
+ * Description: This function return the number of redundant sign bits in a
+ * 32 bit number. Example: qm_norm32(0x00000080) = 23
+ */
s16 qm_norm32(s32 op)
{
u16 u16extraSignBits;
@@ -208,28 +215,30 @@ static const s16 log_table[] = {
32024
};
-#define LOG_TABLE_SIZE 32 /* log_table size */
-#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
-#define Q_LOG_TABLE 15 /* qformat of log_table */
-#define LOG10_2 19728 /* log10(2) in q.16 */
+#define LOG_TABLE_SIZE 32 /* log_table size */
+#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */
+#define Q_LOG_TABLE 15 /* qformat of log_table */
+#define LOG10_2 19728 /* log10(2) in q.16 */
/*
-Description:
-This routine takes the input number N and its q format qN and compute
-the log10(N). This routine first normalizes the input no N. Then N is in mag*(2^x) format.
-mag is any number in the range 2^30-(2^31 - 1). Then log2(mag * 2^x) = log2(mag) + x is computed.
-From that log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
-This routine looks the log2 value in the table considering LOG2_LOG_TABLE_SIZE+1 MSBs.
-As the MSB is always 1, only next LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup.
-Next 16 MSBs are used for interpolation.
-Inputs:
-N - number to which log10 has to be found.
-qN - q format of N
-log10N - address where log10(N) will be written.
-qLog10N - address where log10N qformat will be written.
-Note/Problem:
-For accurate results input should be in normalized or near normalized form.
-*/
+ * Description:
+ * This routine takes the input number N and its q format qN and compute
+ * the log10(N). This routine first normalizes the input no N. Then N is in
+ * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1).
+ * Then log2(mag * 2^x) = log2(mag) + x is computed. From that
+ * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed.
+ * This routine looks the log2 value in the table considering
+ * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next
+ * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used
+ * for interpolation.
+ * Inputs:
+ * N - number to which log10 has to be found.
+ * qN - q format of N
+ * log10N - address where log10(N) will be written.
+ * qLog10N - address where log10N qformat will be written.
+ * Note/Problem:
+ * For accurate results input should be in normalized or near normalized form.
+ */
void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
{
s16 s16norm, s16tableIndex, s16errorApproximation;
@@ -248,12 +257,13 @@ void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
*/
qN = qN + s16norm - 30;
- /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the MSB */
+ /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the
+ * MSB */
s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE)));
/* remove the MSB. the MSB is always 1 after normalization. */
s16tableIndex =
- s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);
+ s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1);
/* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */
N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1);
@@ -263,23 +273,27 @@ void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N)
u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16)));
/* look the log value in the table. */
- s32log = log_table[s16tableIndex]; /* q.15 format */
+ s32log = log_table[s16tableIndex]; /* q.15 format */
- /* interpolate using the offset. */
- s16errorApproximation = (s16) qm_mulu16(u16offset, (u16) (log_table[s16tableIndex + 1] - log_table[s16tableIndex])); /* q.15 */
+ /* interpolate using the offset. q.15 format. */
+ s16errorApproximation = (s16) qm_mulu16(u16offset,
+ (u16) (log_table[s16tableIndex + 1] -
+ log_table[s16tableIndex]));
- s32log = qm_add16((s16) s32log, s16errorApproximation); /* q.15 format */
+ /* q.15 format */
+ s32log = qm_add16((s16) s32log, s16errorApproximation);
/* adjust for the qformat of the N as
* log2(mag * 2^x) = log2(mag) + x
*/
- s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */
+ s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */
/* normalize the result. */
s16norm = qm_norm32(s32log);
/* bring all the important bits into lower 16 bits */
- s32log = qm_shl32(s32log, s16norm - 16); /* q.15+s16norm-16 format */
+ /* q.15+s16norm-16 format */
+ s32log = qm_shl32(s32log, s16norm - 16);
/* compute the log10(N) by multiplying log2(N) with log10(2).
* as log10(mag * 2^x) = log2(mag * 2^x) * log10(2)
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/staging/brcm80211/brcmsmac/phy/phytbl_lcn.c
index 023d05aa97ad..622c01ca72c5 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phytbl_lcn.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phytbl_lcn.c
@@ -17,7 +17,7 @@
#include <types.h>
#include "phytbl_lcn.h"
-const u32 dot11lcn_gain_tbl_rev0[] = {
+static const u32 dot11lcn_gain_tbl_rev0[] = {
0x00000000,
0x00000000,
0x00000000,
@@ -116,7 +116,7 @@ const u32 dot11lcn_gain_tbl_rev0[] = {
0x00000000,
};
-const u32 dot11lcn_gain_tbl_rev1[] = {
+static const u32 dot11lcn_gain_tbl_rev1[] = {
0x00000000,
0x00000000,
0x00000000,
@@ -215,7 +215,7 @@ const u32 dot11lcn_gain_tbl_rev1[] = {
0x00000000,
};
-const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = {
+static const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = {
0x0401,
0x0402,
0x0403,
@@ -256,7 +256,7 @@ const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = {
0x0000,
};
-const u32 dot11lcn_gain_idx_tbl_rev0[] = {
+static const u32 dot11lcn_gain_idx_tbl_rev0[] = {
0x00000000,
0x00000000,
0x10000000,
@@ -407,7 +407,7 @@ const u32 dot11lcn_gain_idx_tbl_rev0[] = {
0x0000001c,
};
-const u16 dot11lcn_aux_gain_idx_tbl_2G[] = {
+static const u16 dot11lcn_aux_gain_idx_tbl_2G[] = {
0x0000,
0x0000,
0x0000,
@@ -448,7 +448,7 @@ const u16 dot11lcn_aux_gain_idx_tbl_2G[] = {
0x0000
};
-const u8 dot11lcn_gain_val_tbl_2G[] = {
+static const u8 dot11lcn_gain_val_tbl_2G[] = {
0xfc,
0x02,
0x08,
@@ -519,7 +519,7 @@ const u8 dot11lcn_gain_val_tbl_2G[] = {
0x00
};
-const u32 dot11lcn_gain_idx_tbl_2G[] = {
+static const u32 dot11lcn_gain_idx_tbl_2G[] = {
0x00000000,
0x00000000,
0x00000000,
@@ -674,7 +674,7 @@ const u32 dot11lcn_gain_idx_tbl_2G[] = {
0x00000000
};
-const u32 dot11lcn_gain_tbl_2G[] = {
+static const u32 dot11lcn_gain_tbl_2G[] = {
0x00000000,
0x00000004,
0x00000008,
@@ -773,7 +773,7 @@ const u32 dot11lcn_gain_tbl_2G[] = {
0x00000000
};
-const u32 dot11lcn_gain_tbl_extlna_2G[] = {
+static const u32 dot11lcn_gain_tbl_extlna_2G[] = {
0x00000000,
0x00000004,
0x00000008,
@@ -872,7 +872,7 @@ const u32 dot11lcn_gain_tbl_extlna_2G[] = {
0x00000000
};
-const u16 dot11lcn_aux_gain_idx_tbl_extlna_2G[] = {
+static const u16 dot11lcn_aux_gain_idx_tbl_extlna_2G[] = {
0x0400,
0x0400,
0x0400,
@@ -913,7 +913,7 @@ const u16 dot11lcn_aux_gain_idx_tbl_extlna_2G[] = {
0x0000
};
-const u8 dot11lcn_gain_val_tbl_extlna_2G[] = {
+static const u8 dot11lcn_gain_val_tbl_extlna_2G[] = {
0xfc,
0x02,
0x08,
@@ -984,7 +984,7 @@ const u8 dot11lcn_gain_val_tbl_extlna_2G[] = {
0x00
};
-const u32 dot11lcn_gain_idx_tbl_extlna_2G[] = {
+static const u32 dot11lcn_gain_idx_tbl_extlna_2G[] = {
0x00000000,
0x00000040,
0x00000000,
@@ -1139,7 +1139,7 @@ const u32 dot11lcn_gain_idx_tbl_extlna_2G[] = {
0x00000000
};
-const u32 dot11lcn_aux_gain_idx_tbl_5G[] = {
+static const u32 dot11lcn_aux_gain_idx_tbl_5G[] = {
0x0000,
0x0000,
0x0000,
@@ -1180,7 +1180,7 @@ const u32 dot11lcn_aux_gain_idx_tbl_5G[] = {
0x0000
};
-const u32 dot11lcn_gain_val_tbl_5G[] = {
+static const u32 dot11lcn_gain_val_tbl_5G[] = {
0xf7,
0xfd,
0x00,
@@ -1251,7 +1251,7 @@ const u32 dot11lcn_gain_val_tbl_5G[] = {
0x00
};
-const u32 dot11lcn_gain_idx_tbl_5G[] = {
+static const u32 dot11lcn_gain_idx_tbl_5G[] = {
0x00000000,
0x00000000,
0x00000000,
@@ -1406,7 +1406,7 @@ const u32 dot11lcn_gain_idx_tbl_5G[] = {
0x00000000
};
-const u32 dot11lcn_gain_tbl_5G[] = {
+static const u32 dot11lcn_gain_tbl_5G[] = {
0x00000000,
0x00000040,
0x00000080,
@@ -1520,7 +1520,7 @@ const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[] = {
,
};
-const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev1[] = {
+static const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev1[] = {
{&dot11lcn_gain_tbl_rev1,
sizeof(dot11lcn_gain_tbl_rev1) / sizeof(dot11lcn_gain_tbl_rev1[0]), 18,
0, 32}
@@ -1611,10 +1611,6 @@ const u32 dot11lcnphytbl_rx_gain_info_sz_rev0 =
sizeof(dot11lcnphytbl_rx_gain_info_rev0) /
sizeof(dot11lcnphytbl_rx_gain_info_rev0[0]);
-const u32 dot11lcnphytbl_rx_gain_info_sz_rev1 =
- sizeof(dot11lcnphytbl_rx_gain_info_rev1) /
- sizeof(dot11lcnphytbl_rx_gain_info_rev1[0]);
-
const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz =
sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2) /
sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2[0]);
@@ -1623,7 +1619,7 @@ const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz =
sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2) /
sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2[0]);
-const u16 dot11lcn_min_sig_sq_tbl_rev0[] = {
+static const u16 dot11lcn_min_sig_sq_tbl_rev0[] = {
0x014d,
0x014d,
0x014d,
@@ -1690,7 +1686,7 @@ const u16 dot11lcn_min_sig_sq_tbl_rev0[] = {
0x014d,
};
-const u16 dot11lcn_noise_scale_tbl_rev0[] = {
+static const u16 dot11lcn_noise_scale_tbl_rev0[] = {
0x0000,
0x0000,
0x0000,
@@ -1757,7 +1753,7 @@ const u16 dot11lcn_noise_scale_tbl_rev0[] = {
0x0000,
};
-const u32 dot11lcn_fltr_ctrl_tbl_rev0[] = {
+static const u32 dot11lcn_fltr_ctrl_tbl_rev0[] = {
0x000141f8,
0x000021f8,
0x000021fb,
@@ -1770,7 +1766,7 @@ const u32 dot11lcn_fltr_ctrl_tbl_rev0[] = {
0x0000024b,
};
-const u32 dot11lcn_ps_ctrl_tbl_rev0[] = {
+static const u32 dot11lcn_ps_ctrl_tbl_rev0[] = {
0x00100001,
0x00200010,
0x00300001,
@@ -1793,7 +1789,7 @@ const u32 dot11lcn_ps_ctrl_tbl_rev0[] = {
0x00600f22,
};
-const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[] = {
+static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[] = {
0x0007,
0x0005,
0x0006,
@@ -1861,7 +1857,7 @@ const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[] = {
};
-const u16 dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[] = {
+static const u16 dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[] = {
0x0007,
0x0005,
0x0002,
@@ -1928,7 +1924,7 @@ const u16 dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[] = {
0x0002,
};
-const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
+static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
0x0002,
0x0008,
0x0004,
@@ -1995,7 +1991,7 @@ const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
0x0001,
};
-const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
+static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
0x000a,
0x0009,
0x0006,
@@ -2062,7 +2058,7 @@ const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
0x0005,
};
-const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
+static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
0x0004,
0x0004,
0x0002,
@@ -2129,7 +2125,7 @@ const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
0x0002,
};
-const u8 dot11lcn_nf_table_rev0[] = {
+static const u8 dot11lcn_nf_table_rev0[] = {
0x5f,
0x36,
0x29,
@@ -2148,7 +2144,7 @@ const u8 dot11lcn_nf_table_rev0[] = {
0x1f,
};
-const u8 dot11lcn_gain_val_tbl_rev0[] = {
+static const u8 dot11lcn_gain_val_tbl_rev0[] = {
0x09,
0x0f,
0x14,
@@ -2211,7 +2207,7 @@ const u8 dot11lcn_gain_val_tbl_rev0[] = {
0x00,
};
-const u8 dot11lcn_spur_tbl_rev0[] = {
+static const u8 dot11lcn_spur_tbl_rev0[] = {
0x01,
0x01,
0x01,
@@ -2342,7 +2338,7 @@ const u8 dot11lcn_spur_tbl_rev0[] = {
0x01,
};
-const u16 dot11lcn_unsup_mcs_tbl_rev0[] = {
+static const u16 dot11lcn_unsup_mcs_tbl_rev0[] = {
0x001a,
0x0034,
0x004e,
@@ -2499,7 +2495,7 @@ const u16 dot11lcn_unsup_mcs_tbl_rev0[] = {
0x06f6,
};
-const u16 dot11lcn_iq_local_tbl_rev0[] = {
+static const u16 dot11lcn_iq_local_tbl_rev0[] = {
0x0200,
0x0300,
0x0400,
@@ -2610,7 +2606,7 @@ const u16 dot11lcn_iq_local_tbl_rev0[] = {
0x0000,
};
-const u32 dot11lcn_papd_compdelta_tbl_rev0[] = {
+static const u32 dot11lcn_papd_compdelta_tbl_rev0[] = {
0x00080000,
0x00080000,
0x00080000,
@@ -2834,26 +2830,26 @@ const struct phytbl_info dot11lcnphytbl_info_rev0[] = {
const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = {
&dot11lcn_sw_ctrl_tbl_4313_rev0,
- sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0) /
- sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16
};
const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa = {
&dot11lcn_sw_ctrl_tbl_4313_epa_rev0,
- sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0) /
- sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0[0]), 15, 0, 16
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0[0]), 15, 0, 16
};
const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa = {
&dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo,
- sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo) /
- sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[0]), 15, 0, 16
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[0]), 15, 0, 16
};
const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250 = {
&dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0,
- sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0) /
- sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[0]), 15, 0, 16
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0) /
+ sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[0]), 15, 0, 16
};
const u32 dot11lcnphytbl_info_sz_rev0 =
@@ -2861,778 +2857,394 @@ const u32 dot11lcnphytbl_info_sz_rev0 =
const struct lcnphy_tx_gain_tbl_entry
dot11lcnphy_2GHz_extPA_gaintable_rev0[128] = {
- {3, 0, 31, 0, 72,}
- ,
- {3, 0, 31, 0, 70,}
- ,
- {3, 0, 31, 0, 68,}
- ,
- {3, 0, 30, 0, 67,}
- ,
- {3, 0, 29, 0, 68,}
- ,
- {3, 0, 28, 0, 68,}
- ,
- {3, 0, 27, 0, 69,}
- ,
- {3, 0, 26, 0, 70,}
- ,
- {3, 0, 25, 0, 70,}
- ,
- {3, 0, 24, 0, 71,}
- ,
- {3, 0, 23, 0, 72,}
- ,
- {3, 0, 23, 0, 70,}
- ,
- {3, 0, 22, 0, 71,}
- ,
- {3, 0, 21, 0, 72,}
- ,
- {3, 0, 21, 0, 70,}
- ,
- {3, 0, 21, 0, 68,}
- ,
- {3, 0, 21, 0, 66,}
- ,
- {3, 0, 21, 0, 64,}
- ,
- {3, 0, 21, 0, 63,}
- ,
- {3, 0, 20, 0, 64,}
- ,
- {3, 0, 19, 0, 65,}
- ,
- {3, 0, 19, 0, 64,}
- ,
- {3, 0, 18, 0, 65,}
- ,
- {3, 0, 18, 0, 64,}
- ,
- {3, 0, 17, 0, 65,}
- ,
- {3, 0, 17, 0, 64,}
- ,
- {3, 0, 16, 0, 65,}
- ,
- {3, 0, 16, 0, 64,}
- ,
- {3, 0, 16, 0, 62,}
- ,
- {3, 0, 16, 0, 60,}
- ,
- {3, 0, 16, 0, 58,}
- ,
- {3, 0, 15, 0, 61,}
- ,
- {3, 0, 15, 0, 59,}
- ,
- {3, 0, 14, 0, 61,}
- ,
- {3, 0, 14, 0, 60,}
- ,
- {3, 0, 14, 0, 58,}
- ,
- {3, 0, 13, 0, 60,}
- ,
- {3, 0, 13, 0, 59,}
- ,
- {3, 0, 12, 0, 62,}
- ,
- {3, 0, 12, 0, 60,}
- ,
- {3, 0, 12, 0, 58,}
- ,
- {3, 0, 11, 0, 62,}
- ,
- {3, 0, 11, 0, 60,}
- ,
- {3, 0, 11, 0, 59,}
- ,
- {3, 0, 11, 0, 57,}
- ,
- {3, 0, 10, 0, 61,}
- ,
- {3, 0, 10, 0, 59,}
- ,
- {3, 0, 10, 0, 57,}
- ,
- {3, 0, 9, 0, 62,}
- ,
- {3, 0, 9, 0, 60,}
- ,
- {3, 0, 9, 0, 58,}
- ,
- {3, 0, 9, 0, 57,}
- ,
- {3, 0, 8, 0, 62,}
- ,
- {3, 0, 8, 0, 60,}
- ,
- {3, 0, 8, 0, 58,}
- ,
- {3, 0, 8, 0, 57,}
- ,
- {3, 0, 8, 0, 55,}
- ,
- {3, 0, 7, 0, 61,}
- ,
- {3, 0, 7, 0, 60,}
- ,
- {3, 0, 7, 0, 58,}
- ,
- {3, 0, 7, 0, 56,}
- ,
- {3, 0, 7, 0, 55,}
- ,
- {3, 0, 6, 0, 62,}
- ,
- {3, 0, 6, 0, 60,}
- ,
- {3, 0, 6, 0, 58,}
- ,
- {3, 0, 6, 0, 57,}
- ,
- {3, 0, 6, 0, 55,}
- ,
- {3, 0, 6, 0, 54,}
- ,
- {3, 0, 6, 0, 52,}
- ,
- {3, 0, 5, 0, 61,}
- ,
- {3, 0, 5, 0, 59,}
- ,
- {3, 0, 5, 0, 57,}
- ,
- {3, 0, 5, 0, 56,}
- ,
- {3, 0, 5, 0, 54,}
- ,
- {3, 0, 5, 0, 53,}
- ,
- {3, 0, 5, 0, 51,}
- ,
- {3, 0, 4, 0, 62,}
- ,
- {3, 0, 4, 0, 60,}
- ,
- {3, 0, 4, 0, 58,}
- ,
- {3, 0, 4, 0, 57,}
- ,
- {3, 0, 4, 0, 55,}
- ,
- {3, 0, 4, 0, 54,}
- ,
- {3, 0, 4, 0, 52,}
- ,
- {3, 0, 4, 0, 51,}
- ,
- {3, 0, 4, 0, 49,}
- ,
- {3, 0, 4, 0, 48,}
- ,
- {3, 0, 4, 0, 46,}
- ,
- {3, 0, 3, 0, 60,}
- ,
- {3, 0, 3, 0, 58,}
- ,
- {3, 0, 3, 0, 57,}
- ,
- {3, 0, 3, 0, 55,}
- ,
- {3, 0, 3, 0, 54,}
- ,
- {3, 0, 3, 0, 52,}
- ,
- {3, 0, 3, 0, 51,}
- ,
- {3, 0, 3, 0, 49,}
- ,
- {3, 0, 3, 0, 48,}
- ,
- {3, 0, 3, 0, 46,}
- ,
- {3, 0, 3, 0, 45,}
- ,
- {3, 0, 3, 0, 44,}
- ,
- {3, 0, 3, 0, 43,}
- ,
- {3, 0, 3, 0, 41,}
- ,
- {3, 0, 2, 0, 61,}
- ,
- {3, 0, 2, 0, 59,}
- ,
- {3, 0, 2, 0, 57,}
- ,
- {3, 0, 2, 0, 56,}
- ,
- {3, 0, 2, 0, 54,}
- ,
- {3, 0, 2, 0, 53,}
- ,
- {3, 0, 2, 0, 51,}
- ,
- {3, 0, 2, 0, 50,}
- ,
- {3, 0, 2, 0, 48,}
- ,
- {3, 0, 2, 0, 47,}
- ,
- {3, 0, 2, 0, 46,}
- ,
- {3, 0, 2, 0, 44,}
- ,
- {3, 0, 2, 0, 43,}
- ,
- {3, 0, 2, 0, 42,}
- ,
- {3, 0, 2, 0, 41,}
- ,
- {3, 0, 2, 0, 39,}
- ,
- {3, 0, 2, 0, 38,}
- ,
- {3, 0, 2, 0, 37,}
- ,
- {3, 0, 2, 0, 36,}
- ,
- {3, 0, 2, 0, 35,}
- ,
- {3, 0, 2, 0, 34,}
- ,
- {3, 0, 2, 0, 33,}
- ,
- {3, 0, 2, 0, 32,}
- ,
- {3, 0, 1, 0, 63,}
- ,
- {3, 0, 1, 0, 61,}
- ,
- {3, 0, 1, 0, 59,}
- ,
- {3, 0, 1, 0, 57,}
- ,
+ {3, 0, 31, 0, 72},
+ {3, 0, 31, 0, 70},
+ {3, 0, 31, 0, 68},
+ {3, 0, 30, 0, 67},
+ {3, 0, 29, 0, 68},
+ {3, 0, 28, 0, 68},
+ {3, 0, 27, 0, 69},
+ {3, 0, 26, 0, 70},
+ {3, 0, 25, 0, 70},
+ {3, 0, 24, 0, 71},
+ {3, 0, 23, 0, 72},
+ {3, 0, 23, 0, 70},
+ {3, 0, 22, 0, 71},
+ {3, 0, 21, 0, 72},
+ {3, 0, 21, 0, 70},
+ {3, 0, 21, 0, 68},
+ {3, 0, 21, 0, 66},
+ {3, 0, 21, 0, 64},
+ {3, 0, 21, 0, 63},
+ {3, 0, 20, 0, 64},
+ {3, 0, 19, 0, 65},
+ {3, 0, 19, 0, 64},
+ {3, 0, 18, 0, 65},
+ {3, 0, 18, 0, 64},
+ {3, 0, 17, 0, 65},
+ {3, 0, 17, 0, 64},
+ {3, 0, 16, 0, 65},
+ {3, 0, 16, 0, 64},
+ {3, 0, 16, 0, 62},
+ {3, 0, 16, 0, 60},
+ {3, 0, 16, 0, 58},
+ {3, 0, 15, 0, 61},
+ {3, 0, 15, 0, 59},
+ {3, 0, 14, 0, 61},
+ {3, 0, 14, 0, 60},
+ {3, 0, 14, 0, 58},
+ {3, 0, 13, 0, 60},
+ {3, 0, 13, 0, 59},
+ {3, 0, 12, 0, 62},
+ {3, 0, 12, 0, 60},
+ {3, 0, 12, 0, 58},
+ {3, 0, 11, 0, 62},
+ {3, 0, 11, 0, 60},
+ {3, 0, 11, 0, 59},
+ {3, 0, 11, 0, 57},
+ {3, 0, 10, 0, 61},
+ {3, 0, 10, 0, 59},
+ {3, 0, 10, 0, 57},
+ {3, 0, 9, 0, 62},
+ {3, 0, 9, 0, 60},
+ {3, 0, 9, 0, 58},
+ {3, 0, 9, 0, 57},
+ {3, 0, 8, 0, 62},
+ {3, 0, 8, 0, 60},
+ {3, 0, 8, 0, 58},
+ {3, 0, 8, 0, 57},
+ {3, 0, 8, 0, 55},
+ {3, 0, 7, 0, 61},
+ {3, 0, 7, 0, 60},
+ {3, 0, 7, 0, 58},
+ {3, 0, 7, 0, 56},
+ {3, 0, 7, 0, 55},
+ {3, 0, 6, 0, 62},
+ {3, 0, 6, 0, 60},
+ {3, 0, 6, 0, 58},
+ {3, 0, 6, 0, 57},
+ {3, 0, 6, 0, 55},
+ {3, 0, 6, 0, 54},
+ {3, 0, 6, 0, 52},
+ {3, 0, 5, 0, 61},
+ {3, 0, 5, 0, 59},
+ {3, 0, 5, 0, 57},
+ {3, 0, 5, 0, 56},
+ {3, 0, 5, 0, 54},
+ {3, 0, 5, 0, 53},
+ {3, 0, 5, 0, 51},
+ {3, 0, 4, 0, 62},
+ {3, 0, 4, 0, 60},
+ {3, 0, 4, 0, 58},
+ {3, 0, 4, 0, 57},
+ {3, 0, 4, 0, 55},
+ {3, 0, 4, 0, 54},
+ {3, 0, 4, 0, 52},
+ {3, 0, 4, 0, 51},
+ {3, 0, 4, 0, 49},
+ {3, 0, 4, 0, 48},
+ {3, 0, 4, 0, 46},
+ {3, 0, 3, 0, 60},
+ {3, 0, 3, 0, 58},
+ {3, 0, 3, 0, 57},
+ {3, 0, 3, 0, 55},
+ {3, 0, 3, 0, 54},
+ {3, 0, 3, 0, 52},
+ {3, 0, 3, 0, 51},
+ {3, 0, 3, 0, 49},
+ {3, 0, 3, 0, 48},
+ {3, 0, 3, 0, 46},
+ {3, 0, 3, 0, 45},
+ {3, 0, 3, 0, 44},
+ {3, 0, 3, 0, 43},
+ {3, 0, 3, 0, 41},
+ {3, 0, 2, 0, 61},
+ {3, 0, 2, 0, 59},
+ {3, 0, 2, 0, 57},
+ {3, 0, 2, 0, 56},
+ {3, 0, 2, 0, 54},
+ {3, 0, 2, 0, 53},
+ {3, 0, 2, 0, 51},
+ {3, 0, 2, 0, 50},
+ {3, 0, 2, 0, 48},
+ {3, 0, 2, 0, 47},
+ {3, 0, 2, 0, 46},
+ {3, 0, 2, 0, 44},
+ {3, 0, 2, 0, 43},
+ {3, 0, 2, 0, 42},
+ {3, 0, 2, 0, 41},
+ {3, 0, 2, 0, 39},
+ {3, 0, 2, 0, 38},
+ {3, 0, 2, 0, 37},
+ {3, 0, 2, 0, 36},
+ {3, 0, 2, 0, 35},
+ {3, 0, 2, 0, 34},
+ {3, 0, 2, 0, 33},
+ {3, 0, 2, 0, 32},
+ {3, 0, 1, 0, 63},
+ {3, 0, 1, 0, 61},
+ {3, 0, 1, 0, 59},
+ {3, 0, 1, 0, 57},
};
const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[128] = {
- {7, 0, 31, 0, 72,}
- ,
- {7, 0, 31, 0, 70,}
- ,
- {7, 0, 31, 0, 68,}
- ,
- {7, 0, 30, 0, 67,}
- ,
- {7, 0, 29, 0, 68,}
- ,
- {7, 0, 28, 0, 68,}
- ,
- {7, 0, 27, 0, 69,}
- ,
- {7, 0, 26, 0, 70,}
- ,
- {7, 0, 25, 0, 70,}
- ,
- {7, 0, 24, 0, 71,}
- ,
- {7, 0, 23, 0, 72,}
- ,
- {7, 0, 23, 0, 70,}
- ,
- {7, 0, 22, 0, 71,}
- ,
- {7, 0, 21, 0, 72,}
- ,
- {7, 0, 21, 0, 70,}
- ,
- {7, 0, 21, 0, 68,}
- ,
- {7, 0, 21, 0, 66,}
- ,
- {7, 0, 21, 0, 64,}
- ,
- {7, 0, 21, 0, 63,}
- ,
- {7, 0, 20, 0, 64,}
- ,
- {7, 0, 19, 0, 65,}
- ,
- {7, 0, 19, 0, 64,}
- ,
- {7, 0, 18, 0, 65,}
- ,
- {7, 0, 18, 0, 64,}
- ,
- {7, 0, 17, 0, 65,}
- ,
- {7, 0, 17, 0, 64,}
- ,
- {7, 0, 16, 0, 65,}
- ,
- {7, 0, 16, 0, 64,}
- ,
- {7, 0, 16, 0, 62,}
- ,
- {7, 0, 16, 0, 60,}
- ,
- {7, 0, 16, 0, 58,}
- ,
- {7, 0, 15, 0, 61,}
- ,
- {7, 0, 15, 0, 59,}
- ,
- {7, 0, 14, 0, 61,}
- ,
- {7, 0, 14, 0, 60,}
- ,
- {7, 0, 14, 0, 58,}
- ,
- {7, 0, 13, 0, 60,}
- ,
- {7, 0, 13, 0, 59,}
- ,
- {7, 0, 12, 0, 62,}
- ,
- {7, 0, 12, 0, 60,}
- ,
- {7, 0, 12, 0, 58,}
- ,
- {7, 0, 11, 0, 62,}
- ,
- {7, 0, 11, 0, 60,}
- ,
- {7, 0, 11, 0, 59,}
- ,
- {7, 0, 11, 0, 57,}
- ,
- {7, 0, 10, 0, 61,}
- ,
- {7, 0, 10, 0, 59,}
- ,
- {7, 0, 10, 0, 57,}
- ,
- {7, 0, 9, 0, 62,}
- ,
- {7, 0, 9, 0, 60,}
- ,
- {7, 0, 9, 0, 58,}
- ,
- {7, 0, 9, 0, 57,}
- ,
- {7, 0, 8, 0, 62,}
- ,
- {7, 0, 8, 0, 60,}
- ,
- {7, 0, 8, 0, 58,}
- ,
- {7, 0, 8, 0, 57,}
- ,
- {7, 0, 8, 0, 55,}
- ,
- {7, 0, 7, 0, 61,}
- ,
- {7, 0, 7, 0, 60,}
- ,
- {7, 0, 7, 0, 58,}
- ,
- {7, 0, 7, 0, 56,}
- ,
- {7, 0, 7, 0, 55,}
- ,
- {7, 0, 6, 0, 62,}
- ,
- {7, 0, 6, 0, 60,}
- ,
- {7, 0, 6, 0, 58,}
- ,
- {7, 0, 6, 0, 57,}
- ,
- {7, 0, 6, 0, 55,}
- ,
- {7, 0, 6, 0, 54,}
- ,
- {7, 0, 6, 0, 52,}
- ,
- {7, 0, 5, 0, 61,}
- ,
- {7, 0, 5, 0, 59,}
- ,
- {7, 0, 5, 0, 57,}
- ,
- {7, 0, 5, 0, 56,}
- ,
- {7, 0, 5, 0, 54,}
- ,
- {7, 0, 5, 0, 53,}
- ,
- {7, 0, 5, 0, 51,}
- ,
- {7, 0, 4, 0, 62,}
- ,
- {7, 0, 4, 0, 60,}
- ,
- {7, 0, 4, 0, 58,}
- ,
- {7, 0, 4, 0, 57,}
- ,
- {7, 0, 4, 0, 55,}
- ,
- {7, 0, 4, 0, 54,}
- ,
- {7, 0, 4, 0, 52,}
- ,
- {7, 0, 4, 0, 51,}
- ,
- {7, 0, 4, 0, 49,}
- ,
- {7, 0, 4, 0, 48,}
- ,
- {7, 0, 4, 0, 46,}
- ,
- {7, 0, 3, 0, 60,}
- ,
- {7, 0, 3, 0, 58,}
- ,
- {7, 0, 3, 0, 57,}
- ,
- {7, 0, 3, 0, 55,}
- ,
- {7, 0, 3, 0, 54,}
- ,
- {7, 0, 3, 0, 52,}
- ,
- {7, 0, 3, 0, 51,}
- ,
- {7, 0, 3, 0, 49,}
- ,
- {7, 0, 3, 0, 48,}
- ,
- {7, 0, 3, 0, 46,}
- ,
- {7, 0, 3, 0, 45,}
- ,
- {7, 0, 3, 0, 44,}
- ,
- {7, 0, 3, 0, 43,}
- ,
- {7, 0, 3, 0, 41,}
- ,
- {7, 0, 2, 0, 61,}
- ,
- {7, 0, 2, 0, 59,}
- ,
- {7, 0, 2, 0, 57,}
- ,
- {7, 0, 2, 0, 56,}
- ,
- {7, 0, 2, 0, 54,}
- ,
- {7, 0, 2, 0, 53,}
- ,
- {7, 0, 2, 0, 51,}
- ,
- {7, 0, 2, 0, 50,}
- ,
- {7, 0, 2, 0, 48,}
- ,
- {7, 0, 2, 0, 47,}
- ,
- {7, 0, 2, 0, 46,}
- ,
- {7, 0, 2, 0, 44,}
- ,
- {7, 0, 2, 0, 43,}
- ,
- {7, 0, 2, 0, 42,}
- ,
- {7, 0, 2, 0, 41,}
- ,
- {7, 0, 2, 0, 39,}
- ,
- {7, 0, 2, 0, 38,}
- ,
- {7, 0, 2, 0, 37,}
- ,
- {7, 0, 2, 0, 36,}
- ,
- {7, 0, 2, 0, 35,}
- ,
- {7, 0, 2, 0, 34,}
- ,
- {7, 0, 2, 0, 33,}
- ,
- {7, 0, 2, 0, 32,}
- ,
- {7, 0, 1, 0, 63,}
- ,
- {7, 0, 1, 0, 61,}
- ,
- {7, 0, 1, 0, 59,}
- ,
- {7, 0, 1, 0, 57,}
- ,
+ {7, 0, 31, 0, 72},
+ {7, 0, 31, 0, 70},
+ {7, 0, 31, 0, 68},
+ {7, 0, 30, 0, 67},
+ {7, 0, 29, 0, 68},
+ {7, 0, 28, 0, 68},
+ {7, 0, 27, 0, 69},
+ {7, 0, 26, 0, 70},
+ {7, 0, 25, 0, 70},
+ {7, 0, 24, 0, 71},
+ {7, 0, 23, 0, 72},
+ {7, 0, 23, 0, 70},
+ {7, 0, 22, 0, 71},
+ {7, 0, 21, 0, 72},
+ {7, 0, 21, 0, 70},
+ {7, 0, 21, 0, 68},
+ {7, 0, 21, 0, 66},
+ {7, 0, 21, 0, 64},
+ {7, 0, 21, 0, 63},
+ {7, 0, 20, 0, 64},
+ {7, 0, 19, 0, 65},
+ {7, 0, 19, 0, 64},
+ {7, 0, 18, 0, 65},
+ {7, 0, 18, 0, 64},
+ {7, 0, 17, 0, 65},
+ {7, 0, 17, 0, 64},
+ {7, 0, 16, 0, 65},
+ {7, 0, 16, 0, 64},
+ {7, 0, 16, 0, 62},
+ {7, 0, 16, 0, 60},
+ {7, 0, 16, 0, 58},
+ {7, 0, 15, 0, 61},
+ {7, 0, 15, 0, 59},
+ {7, 0, 14, 0, 61},
+ {7, 0, 14, 0, 60},
+ {7, 0, 14, 0, 58},
+ {7, 0, 13, 0, 60},
+ {7, 0, 13, 0, 59},
+ {7, 0, 12, 0, 62},
+ {7, 0, 12, 0, 60},
+ {7, 0, 12, 0, 58},
+ {7, 0, 11, 0, 62},
+ {7, 0, 11, 0, 60},
+ {7, 0, 11, 0, 59},
+ {7, 0, 11, 0, 57},
+ {7, 0, 10, 0, 61},
+ {7, 0, 10, 0, 59},
+ {7, 0, 10, 0, 57},
+ {7, 0, 9, 0, 62},
+ {7, 0, 9, 0, 60},
+ {7, 0, 9, 0, 58},
+ {7, 0, 9, 0, 57},
+ {7, 0, 8, 0, 62},
+ {7, 0, 8, 0, 60},
+ {7, 0, 8, 0, 58},
+ {7, 0, 8, 0, 57},
+ {7, 0, 8, 0, 55},
+ {7, 0, 7, 0, 61},
+ {7, 0, 7, 0, 60},
+ {7, 0, 7, 0, 58},
+ {7, 0, 7, 0, 56},
+ {7, 0, 7, 0, 55},
+ {7, 0, 6, 0, 62},
+ {7, 0, 6, 0, 60},
+ {7, 0, 6, 0, 58},
+ {7, 0, 6, 0, 57},
+ {7, 0, 6, 0, 55},
+ {7, 0, 6, 0, 54},
+ {7, 0, 6, 0, 52},
+ {7, 0, 5, 0, 61},
+ {7, 0, 5, 0, 59},
+ {7, 0, 5, 0, 57},
+ {7, 0, 5, 0, 56},
+ {7, 0, 5, 0, 54},
+ {7, 0, 5, 0, 53},
+ {7, 0, 5, 0, 51},
+ {7, 0, 4, 0, 62},
+ {7, 0, 4, 0, 60},
+ {7, 0, 4, 0, 58},
+ {7, 0, 4, 0, 57},
+ {7, 0, 4, 0, 55},
+ {7, 0, 4, 0, 54},
+ {7, 0, 4, 0, 52},
+ {7, 0, 4, 0, 51},
+ {7, 0, 4, 0, 49},
+ {7, 0, 4, 0, 48},
+ {7, 0, 4, 0, 46},
+ {7, 0, 3, 0, 60},
+ {7, 0, 3, 0, 58},
+ {7, 0, 3, 0, 57},
+ {7, 0, 3, 0, 55},
+ {7, 0, 3, 0, 54},
+ {7, 0, 3, 0, 52},
+ {7, 0, 3, 0, 51},
+ {7, 0, 3, 0, 49},
+ {7, 0, 3, 0, 48},
+ {7, 0, 3, 0, 46},
+ {7, 0, 3, 0, 45},
+ {7, 0, 3, 0, 44},
+ {7, 0, 3, 0, 43},
+ {7, 0, 3, 0, 41},
+ {7, 0, 2, 0, 61},
+ {7, 0, 2, 0, 59},
+ {7, 0, 2, 0, 57},
+ {7, 0, 2, 0, 56},
+ {7, 0, 2, 0, 54},
+ {7, 0, 2, 0, 53},
+ {7, 0, 2, 0, 51},
+ {7, 0, 2, 0, 50},
+ {7, 0, 2, 0, 48},
+ {7, 0, 2, 0, 47},
+ {7, 0, 2, 0, 46},
+ {7, 0, 2, 0, 44},
+ {7, 0, 2, 0, 43},
+ {7, 0, 2, 0, 42},
+ {7, 0, 2, 0, 41},
+ {7, 0, 2, 0, 39},
+ {7, 0, 2, 0, 38},
+ {7, 0, 2, 0, 37},
+ {7, 0, 2, 0, 36},
+ {7, 0, 2, 0, 35},
+ {7, 0, 2, 0, 34},
+ {7, 0, 2, 0, 33},
+ {7, 0, 2, 0, 32},
+ {7, 0, 1, 0, 63},
+ {7, 0, 1, 0, 61},
+ {7, 0, 1, 0, 59},
+ {7, 0, 1, 0, 57},
};
const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[128] = {
- {255, 255, 0xf0, 0, 152,}
- ,
- {255, 255, 0xf0, 0, 147,}
- ,
- {255, 255, 0xf0, 0, 143,}
- ,
- {255, 255, 0xf0, 0, 139,}
- ,
- {255, 255, 0xf0, 0, 135,}
- ,
- {255, 255, 0xf0, 0, 131,}
- ,
- {255, 255, 0xf0, 0, 128,}
- ,
- {255, 255, 0xf0, 0, 124,}
- ,
- {255, 255, 0xf0, 0, 121,}
- ,
- {255, 255, 0xf0, 0, 117,}
- ,
- {255, 255, 0xf0, 0, 114,}
- ,
- {255, 255, 0xf0, 0, 111,}
- ,
- {255, 255, 0xf0, 0, 107,}
- ,
- {255, 255, 0xf0, 0, 104,}
- ,
- {255, 255, 0xf0, 0, 101,}
- ,
- {255, 255, 0xf0, 0, 99,}
- ,
- {255, 255, 0xf0, 0, 96,}
- ,
- {255, 255, 0xf0, 0, 93,}
- ,
- {255, 255, 0xf0, 0, 90,}
- ,
- {255, 255, 0xf0, 0, 88,}
- ,
- {255, 255, 0xf0, 0, 85,}
- ,
- {255, 255, 0xf0, 0, 83,}
- ,
- {255, 255, 0xf0, 0, 81,}
- ,
- {255, 255, 0xf0, 0, 78,}
- ,
- {255, 255, 0xf0, 0, 76,}
- ,
- {255, 255, 0xf0, 0, 74,}
- ,
- {255, 255, 0xf0, 0, 72,}
- ,
- {255, 255, 0xf0, 0, 70,}
- ,
- {255, 255, 0xf0, 0, 68,}
- ,
- {255, 255, 0xf0, 0, 66,}
- ,
- {255, 255, 0xf0, 0, 64,}
- ,
- {255, 248, 0xf0, 0, 64,}
- ,
- {255, 241, 0xf0, 0, 64,}
- ,
- {255, 251, 0xe0, 0, 64,}
- ,
- {255, 244, 0xe0, 0, 64,}
- ,
- {255, 254, 0xd0, 0, 64,}
- ,
- {255, 246, 0xd0, 0, 64,}
- ,
- {255, 239, 0xd0, 0, 64,}
- ,
- {255, 249, 0xc0, 0, 64,}
- ,
- {255, 242, 0xc0, 0, 64,}
- ,
- {255, 255, 0xb0, 0, 64,}
- ,
- {255, 248, 0xb0, 0, 64,}
- ,
- {255, 241, 0xb0, 0, 64,}
- ,
- {255, 254, 0xa0, 0, 64,}
- ,
- {255, 246, 0xa0, 0, 64,}
- ,
- {255, 239, 0xa0, 0, 64,}
- ,
- {255, 255, 0x90, 0, 64,}
- ,
- {255, 248, 0x90, 0, 64,}
- ,
- {255, 241, 0x90, 0, 64,}
- ,
- {255, 234, 0x90, 0, 64,}
- ,
- {255, 255, 0x80, 0, 64,}
- ,
- {255, 248, 0x80, 0, 64,}
- ,
- {255, 241, 0x80, 0, 64,}
- ,
- {255, 234, 0x80, 0, 64,}
- ,
- {255, 255, 0x70, 0, 64,}
- ,
- {255, 248, 0x70, 0, 64,}
- ,
- {255, 241, 0x70, 0, 64,}
- ,
- {255, 234, 0x70, 0, 64,}
- ,
- {255, 227, 0x70, 0, 64,}
- ,
- {255, 221, 0x70, 0, 64,}
- ,
- {255, 215, 0x70, 0, 64,}
- ,
- {255, 208, 0x70, 0, 64,}
- ,
- {255, 203, 0x70, 0, 64,}
- ,
- {255, 197, 0x70, 0, 64,}
- ,
- {255, 255, 0x60, 0, 64,}
- ,
- {255, 248, 0x60, 0, 64,}
- ,
- {255, 241, 0x60, 0, 64,}
- ,
- {255, 234, 0x60, 0, 64,}
- ,
- {255, 227, 0x60, 0, 64,}
- ,
- {255, 221, 0x60, 0, 64,}
- ,
- {255, 255, 0x50, 0, 64,}
- ,
- {255, 248, 0x50, 0, 64,}
- ,
- {255, 241, 0x50, 0, 64,}
- ,
- {255, 234, 0x50, 0, 64,}
- ,
- {255, 227, 0x50, 0, 64,}
- ,
- {255, 221, 0x50, 0, 64,}
- ,
- {255, 215, 0x50, 0, 64,}
- ,
- {255, 208, 0x50, 0, 64,}
- ,
- {255, 255, 0x40, 0, 64,}
- ,
- {255, 248, 0x40, 0, 64,}
- ,
- {255, 241, 0x40, 0, 64,}
- ,
- {255, 234, 0x40, 0, 64,}
- ,
- {255, 227, 0x40, 0, 64,}
- ,
- {255, 221, 0x40, 0, 64,}
- ,
- {255, 215, 0x40, 0, 64,}
- ,
- {255, 208, 0x40, 0, 64,}
- ,
- {255, 203, 0x40, 0, 64,}
- ,
- {255, 197, 0x40, 0, 64,}
- ,
- {255, 255, 0x30, 0, 64,}
- ,
- {255, 248, 0x30, 0, 64,}
- ,
- {255, 241, 0x30, 0, 64,}
- ,
- {255, 234, 0x30, 0, 64,}
- ,
- {255, 227, 0x30, 0, 64,}
- ,
- {255, 221, 0x30, 0, 64,}
- ,
- {255, 215, 0x30, 0, 64,}
- ,
- {255, 208, 0x30, 0, 64,}
- ,
- {255, 203, 0x30, 0, 64,}
- ,
- {255, 197, 0x30, 0, 64,}
- ,
- {255, 191, 0x30, 0, 64,}
- ,
- {255, 186, 0x30, 0, 64,}
- ,
- {255, 181, 0x30, 0, 64,}
- ,
- {255, 175, 0x30, 0, 64,}
- ,
- {255, 255, 0x20, 0, 64,}
- ,
- {255, 248, 0x20, 0, 64,}
- ,
- {255, 241, 0x20, 0, 64,}
- ,
- {255, 234, 0x20, 0, 64,}
- ,
- {255, 227, 0x20, 0, 64,}
- ,
- {255, 221, 0x20, 0, 64,}
- ,
- {255, 215, 0x20, 0, 64,}
- ,
- {255, 208, 0x20, 0, 64,}
- ,
- {255, 203, 0x20, 0, 64,}
- ,
- {255, 197, 0x20, 0, 64,}
- ,
- {255, 191, 0x20, 0, 64,}
- ,
- {255, 186, 0x20, 0, 64,}
- ,
- {255, 181, 0x20, 0, 64,}
- ,
- {255, 175, 0x20, 0, 64,}
- ,
- {255, 170, 0x20, 0, 64,}
- ,
- {255, 166, 0x20, 0, 64,}
- ,
- {255, 161, 0x20, 0, 64,}
- ,
- {255, 156, 0x20, 0, 64,}
- ,
- {255, 152, 0x20, 0, 64,}
- ,
- {255, 148, 0x20, 0, 64,}
- ,
- {255, 143, 0x20, 0, 64,}
- ,
- {255, 139, 0x20, 0, 64,}
- ,
- {255, 135, 0x20, 0, 64,}
- ,
- {255, 132, 0x20, 0, 64,}
- ,
- {255, 255, 0x10, 0, 64,}
- ,
- {255, 248, 0x10, 0, 64,}
- ,
+ {255, 255, 0xf0, 0, 152},
+ {255, 255, 0xf0, 0, 147},
+ {255, 255, 0xf0, 0, 143},
+ {255, 255, 0xf0, 0, 139},
+ {255, 255, 0xf0, 0, 135},
+ {255, 255, 0xf0, 0, 131},
+ {255, 255, 0xf0, 0, 128},
+ {255, 255, 0xf0, 0, 124},
+ {255, 255, 0xf0, 0, 121},
+ {255, 255, 0xf0, 0, 117},
+ {255, 255, 0xf0, 0, 114},
+ {255, 255, 0xf0, 0, 111},
+ {255, 255, 0xf0, 0, 107},
+ {255, 255, 0xf0, 0, 104},
+ {255, 255, 0xf0, 0, 101},
+ {255, 255, 0xf0, 0, 99},
+ {255, 255, 0xf0, 0, 96},
+ {255, 255, 0xf0, 0, 93},
+ {255, 255, 0xf0, 0, 90},
+ {255, 255, 0xf0, 0, 88},
+ {255, 255, 0xf0, 0, 85},
+ {255, 255, 0xf0, 0, 83},
+ {255, 255, 0xf0, 0, 81},
+ {255, 255, 0xf0, 0, 78},
+ {255, 255, 0xf0, 0, 76},
+ {255, 255, 0xf0, 0, 74},
+ {255, 255, 0xf0, 0, 72},
+ {255, 255, 0xf0, 0, 70},
+ {255, 255, 0xf0, 0, 68},
+ {255, 255, 0xf0, 0, 66},
+ {255, 255, 0xf0, 0, 64},
+ {255, 248, 0xf0, 0, 64},
+ {255, 241, 0xf0, 0, 64},
+ {255, 251, 0xe0, 0, 64},
+ {255, 244, 0xe0, 0, 64},
+ {255, 254, 0xd0, 0, 64},
+ {255, 246, 0xd0, 0, 64},
+ {255, 239, 0xd0, 0, 64},
+ {255, 249, 0xc0, 0, 64},
+ {255, 242, 0xc0, 0, 64},
+ {255, 255, 0xb0, 0, 64},
+ {255, 248, 0xb0, 0, 64},
+ {255, 241, 0xb0, 0, 64},
+ {255, 254, 0xa0, 0, 64},
+ {255, 246, 0xa0, 0, 64},
+ {255, 239, 0xa0, 0, 64},
+ {255, 255, 0x90, 0, 64},
+ {255, 248, 0x90, 0, 64},
+ {255, 241, 0x90, 0, 64},
+ {255, 234, 0x90, 0, 64},
+ {255, 255, 0x80, 0, 64},
+ {255, 248, 0x80, 0, 64},
+ {255, 241, 0x80, 0, 64},
+ {255, 234, 0x80, 0, 64},
+ {255, 255, 0x70, 0, 64},
+ {255, 248, 0x70, 0, 64},
+ {255, 241, 0x70, 0, 64},
+ {255, 234, 0x70, 0, 64},
+ {255, 227, 0x70, 0, 64},
+ {255, 221, 0x70, 0, 64},
+ {255, 215, 0x70, 0, 64},
+ {255, 208, 0x70, 0, 64},
+ {255, 203, 0x70, 0, 64},
+ {255, 197, 0x70, 0, 64},
+ {255, 255, 0x60, 0, 64},
+ {255, 248, 0x60, 0, 64},
+ {255, 241, 0x60, 0, 64},
+ {255, 234, 0x60, 0, 64},
+ {255, 227, 0x60, 0, 64},
+ {255, 221, 0x60, 0, 64},
+ {255, 255, 0x50, 0, 64},
+ {255, 248, 0x50, 0, 64},
+ {255, 241, 0x50, 0, 64},
+ {255, 234, 0x50, 0, 64},
+ {255, 227, 0x50, 0, 64},
+ {255, 221, 0x50, 0, 64},
+ {255, 215, 0x50, 0, 64},
+ {255, 208, 0x50, 0, 64},
+ {255, 255, 0x40, 0, 64},
+ {255, 248, 0x40, 0, 64},
+ {255, 241, 0x40, 0, 64},
+ {255, 234, 0x40, 0, 64},
+ {255, 227, 0x40, 0, 64},
+ {255, 221, 0x40, 0, 64},
+ {255, 215, 0x40, 0, 64},
+ {255, 208, 0x40, 0, 64},
+ {255, 203, 0x40, 0, 64},
+ {255, 197, 0x40, 0, 64},
+ {255, 255, 0x30, 0, 64},
+ {255, 248, 0x30, 0, 64},
+ {255, 241, 0x30, 0, 64},
+ {255, 234, 0x30, 0, 64},
+ {255, 227, 0x30, 0, 64},
+ {255, 221, 0x30, 0, 64},
+ {255, 215, 0x30, 0, 64},
+ {255, 208, 0x30, 0, 64},
+ {255, 203, 0x30, 0, 64},
+ {255, 197, 0x30, 0, 64},
+ {255, 191, 0x30, 0, 64},
+ {255, 186, 0x30, 0, 64},
+ {255, 181, 0x30, 0, 64},
+ {255, 175, 0x30, 0, 64},
+ {255, 255, 0x20, 0, 64},
+ {255, 248, 0x20, 0, 64},
+ {255, 241, 0x20, 0, 64},
+ {255, 234, 0x20, 0, 64},
+ {255, 227, 0x20, 0, 64},
+ {255, 221, 0x20, 0, 64},
+ {255, 215, 0x20, 0, 64},
+ {255, 208, 0x20, 0, 64},
+ {255, 203, 0x20, 0, 64},
+ {255, 197, 0x20, 0, 64},
+ {255, 191, 0x20, 0, 64},
+ {255, 186, 0x20, 0, 64},
+ {255, 181, 0x20, 0, 64},
+ {255, 175, 0x20, 0, 64},
+ {255, 170, 0x20, 0, 64},
+ {255, 166, 0x20, 0, 64},
+ {255, 161, 0x20, 0, 64},
+ {255, 156, 0x20, 0, 64},
+ {255, 152, 0x20, 0, 64},
+ {255, 148, 0x20, 0, 64},
+ {255, 143, 0x20, 0, 64},
+ {255, 139, 0x20, 0, 64},
+ {255, 135, 0x20, 0, 64},
+ {255, 132, 0x20, 0, 64},
+ {255, 255, 0x10, 0, 64},
+ {255, 248, 0x10, 0, 64},
};
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.c b/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.c
index 7f741f4868a6..dbf50ef6cd75 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.c
@@ -17,7 +17,7 @@
#include <types.h>
#include "phytbl_n.h"
-const u32 frame_struct_rev0[] = {
+static const u32 frame_struct_rev0[] = {
0x08004a04,
0x00100000,
0x01000a05,
@@ -852,7 +852,7 @@ const u32 frame_struct_rev0[] = {
0x00000000,
};
-const u8 frame_lut_rev0[] = {
+static const u8 frame_lut_rev0[] = {
0x02,
0x04,
0x14,
@@ -887,7 +887,7 @@ const u8 frame_lut_rev0[] = {
0x2a,
};
-const u32 tmap_tbl_rev0[] = {
+static const u32 tmap_tbl_rev0[] = {
0x8a88aa80,
0x8aaaaa8a,
0x8a8a8aa8,
@@ -1338,7 +1338,7 @@ const u32 tmap_tbl_rev0[] = {
0x00000000,
};
-const u32 tdtrn_tbl_rev0[] = {
+static const u32 tdtrn_tbl_rev0[] = {
0x061c061c,
0x0050ee68,
0xf592fe36,
@@ -2045,7 +2045,7 @@ const u32 tdtrn_tbl_rev0[] = {
0x00f006be,
};
-const u32 intlv_tbl_rev0[] = {
+static const u32 intlv_tbl_rev0[] = {
0x00802070,
0x0671188d,
0x0a60192c,
@@ -2055,7 +2055,7 @@ const u32 intlv_tbl_rev0[] = {
0x00000070,
};
-const u16 pilot_tbl_rev0[] = {
+static const u16 pilot_tbl_rev0[] = {
0xff08,
0xff08,
0xff08,
@@ -2146,7 +2146,7 @@ const u16 pilot_tbl_rev0[] = {
0xffff,
};
-const u32 pltlut_tbl_rev0[] = {
+static const u32 pltlut_tbl_rev0[] = {
0x76540123,
0x62407351,
0x76543201,
@@ -2155,7 +2155,7 @@ const u32 pltlut_tbl_rev0[] = {
0x76430521,
};
-const u32 tdi_tbl20_ant0_rev0[] = {
+static const u32 tdi_tbl20_ant0_rev0[] = {
0x00091226,
0x000a1429,
0x000b56ad,
@@ -2213,7 +2213,7 @@ const u32 tdi_tbl20_ant0_rev0[] = {
0x00000000,
};
-const u32 tdi_tbl20_ant1_rev0[] = {
+static const u32 tdi_tbl20_ant1_rev0[] = {
0x00014b26,
0x00028d29,
0x000393ad,
@@ -2271,7 +2271,7 @@ const u32 tdi_tbl20_ant1_rev0[] = {
0x00000000,
};
-const u32 tdi_tbl40_ant0_rev0[] = {
+static const u32 tdi_tbl40_ant0_rev0[] = {
0x0011a346,
0x00136ccf,
0x0014f5d9,
@@ -2384,7 +2384,7 @@ const u32 tdi_tbl40_ant0_rev0[] = {
0x00000000,
};
-const u32 tdi_tbl40_ant1_rev0[] = {
+static const u32 tdi_tbl40_ant1_rev0[] = {
0x001edb36,
0x000129ca,
0x0002b353,
@@ -2497,7 +2497,7 @@ const u32 tdi_tbl40_ant1_rev0[] = {
0x00000000,
};
-const u16 bdi_tbl_rev0[] = {
+static const u16 bdi_tbl_rev0[] = {
0x0070,
0x0126,
0x012c,
@@ -2506,7 +2506,7 @@ const u16 bdi_tbl_rev0[] = {
0x04d2,
};
-const u32 chanest_tbl_rev0[] = {
+static const u32 chanest_tbl_rev0[] = {
0x44444444,
0x44444444,
0x44444444,
@@ -2605,7 +2605,7 @@ const u32 chanest_tbl_rev0[] = {
0x10101010,
};
-const u8 mcs_tbl_rev0[] = {
+static const u8 mcs_tbl_rev0[] = {
0x00,
0x08,
0x0a,
@@ -2736,7 +2736,7 @@ const u8 mcs_tbl_rev0[] = {
0x00,
};
-const u32 noise_var_tbl0_rev0[] = {
+static const u32 noise_var_tbl0_rev0[] = {
0x020c020c,
0x0000014d,
0x020c020c,
@@ -2995,7 +2995,7 @@ const u32 noise_var_tbl0_rev0[] = {
0x0000014d,
};
-const u32 noise_var_tbl1_rev0[] = {
+static const u32 noise_var_tbl1_rev0[] = {
0x020c020c,
0x0000014d,
0x020c020c,
@@ -3254,7 +3254,7 @@ const u32 noise_var_tbl1_rev0[] = {
0x0000014d,
};
-const u8 est_pwr_lut_core0_rev0[] = {
+static const u8 est_pwr_lut_core0_rev0[] = {
0x50,
0x4f,
0x4e,
@@ -3321,7 +3321,7 @@ const u8 est_pwr_lut_core0_rev0[] = {
0x11,
};
-const u8 est_pwr_lut_core1_rev0[] = {
+static const u8 est_pwr_lut_core1_rev0[] = {
0x50,
0x4f,
0x4e,
@@ -3388,7 +3388,7 @@ const u8 est_pwr_lut_core1_rev0[] = {
0x11,
};
-const u8 adj_pwr_lut_core0_rev0[] = {
+static const u8 adj_pwr_lut_core0_rev0[] = {
0x00,
0x00,
0x00,
@@ -3519,7 +3519,7 @@ const u8 adj_pwr_lut_core0_rev0[] = {
0x00,
};
-const u8 adj_pwr_lut_core1_rev0[] = {
+static const u8 adj_pwr_lut_core1_rev0[] = {
0x00,
0x00,
0x00,
@@ -3650,7 +3650,7 @@ const u8 adj_pwr_lut_core1_rev0[] = {
0x00,
};
-const u32 gainctrl_lut_core0_rev0[] = {
+static const u32 gainctrl_lut_core0_rev0[] = {
0x03cc2b44,
0x03cc2b42,
0x03cc2b40,
@@ -3781,7 +3781,7 @@ const u32 gainctrl_lut_core0_rev0[] = {
0x00002b00,
};
-const u32 gainctrl_lut_core1_rev0[] = {
+static const u32 gainctrl_lut_core1_rev0[] = {
0x03cc2b44,
0x03cc2b42,
0x03cc2b40,
@@ -3912,7 +3912,7 @@ const u32 gainctrl_lut_core1_rev0[] = {
0x00002b00,
};
-const u32 iq_lut_core0_rev0[] = {
+static const u32 iq_lut_core0_rev0[] = {
0x0000007f,
0x0000007f,
0x0000007f,
@@ -4043,7 +4043,7 @@ const u32 iq_lut_core0_rev0[] = {
0x0000007f,
};
-const u32 iq_lut_core1_rev0[] = {
+static const u32 iq_lut_core1_rev0[] = {
0x0000007f,
0x0000007f,
0x0000007f,
@@ -4174,7 +4174,7 @@ const u32 iq_lut_core1_rev0[] = {
0x0000007f,
};
-const u16 loft_lut_core0_rev0[] = {
+static const u16 loft_lut_core0_rev0[] = {
0x0000,
0x0101,
0x0002,
@@ -4305,7 +4305,7 @@ const u16 loft_lut_core0_rev0[] = {
0x0103,
};
-const u16 loft_lut_core1_rev0[] = {
+static const u16 loft_lut_core1_rev0[] = {
0x0000,
0x0101,
0x0002,
@@ -4522,7 +4522,8 @@ const struct phytbl_info mimophytbl_info_rev0[] = {
{&chanest_tbl_rev0,
sizeof(chanest_tbl_rev0) / sizeof(chanest_tbl_rev0[0]), 22, 0, 32}
,
- {&mcs_tbl_rev0, sizeof(mcs_tbl_rev0) / sizeof(mcs_tbl_rev0[0]), 18, 0, 8}
+ {&mcs_tbl_rev0, sizeof(mcs_tbl_rev0) / sizeof(mcs_tbl_rev0[0]), 18, 0,
+ 8}
,
{&noise_var_tbl0_rev0,
sizeof(noise_var_tbl0_rev0) / sizeof(noise_var_tbl0_rev0[0]), 16, 0,
@@ -4540,7 +4541,7 @@ const u32 mimophytbl_info_sz_rev0_volatile =
sizeof(mimophytbl_info_rev0_volatile) /
sizeof(mimophytbl_info_rev0_volatile[0]);
-const u16 ant_swctrl_tbl_rev3[] = {
+static const u16 ant_swctrl_tbl_rev3[] = {
0x0082,
0x0082,
0x0211,
@@ -4575,7 +4576,7 @@ const u16 ant_swctrl_tbl_rev3[] = {
0x0000,
};
-const u16 ant_swctrl_tbl_rev3_1[] = {
+static const u16 ant_swctrl_tbl_rev3_1[] = {
0x0022,
0x0022,
0x0011,
@@ -4610,7 +4611,7 @@ const u16 ant_swctrl_tbl_rev3_1[] = {
0x0000,
};
-const u16 ant_swctrl_tbl_rev3_2[] = {
+static const u16 ant_swctrl_tbl_rev3_2[] = {
0x0088,
0x0088,
0x0044,
@@ -4645,7 +4646,7 @@ const u16 ant_swctrl_tbl_rev3_2[] = {
0x0000,
};
-const u16 ant_swctrl_tbl_rev3_3[] = {
+static const u16 ant_swctrl_tbl_rev3_3[] = {
0x022,
0x022,
0x011,
@@ -4680,7 +4681,7 @@ const u16 ant_swctrl_tbl_rev3_3[] = {
0x3cc
};
-const u32 frame_struct_rev3[] = {
+static const u32 frame_struct_rev3[] = {
0x08004a04,
0x00100000,
0x01000a05,
@@ -5515,7 +5516,7 @@ const u32 frame_struct_rev3[] = {
0x00000000,
};
-const u16 pilot_tbl_rev3[] = {
+static const u16 pilot_tbl_rev3[] = {
0xff08,
0xff08,
0xff08,
@@ -5606,7 +5607,7 @@ const u16 pilot_tbl_rev3[] = {
0xffff,
};
-const u32 tmap_tbl_rev3[] = {
+static const u32 tmap_tbl_rev3[] = {
0x8a88aa80,
0x8aaaaa8a,
0x8a8a8aa8,
@@ -6057,7 +6058,7 @@ const u32 tmap_tbl_rev3[] = {
0x00000000,
};
-const u32 intlv_tbl_rev3[] = {
+static const u32 intlv_tbl_rev3[] = {
0x00802070,
0x0671188d,
0x0a60192c,
@@ -6067,7 +6068,7 @@ const u32 intlv_tbl_rev3[] = {
0x00000070,
};
-const u32 tdtrn_tbl_rev3[] = {
+static const u32 tdtrn_tbl_rev3[] = {
0x061c061c,
0x0050ee68,
0xf592fe36,
@@ -7033,7 +7034,7 @@ const u32 noise_var_tbl_rev3[] = {
0x0000014d,
};
-const u16 mcs_tbl_rev3[] = {
+static const u16 mcs_tbl_rev3[] = {
0x0000,
0x0008,
0x000a,
@@ -7164,7 +7165,7 @@ const u16 mcs_tbl_rev3[] = {
0x0007,
};
-const u32 tdi_tbl20_ant0_rev3[] = {
+static const u32 tdi_tbl20_ant0_rev3[] = {
0x00091226,
0x000a1429,
0x000b56ad,
@@ -7222,7 +7223,7 @@ const u32 tdi_tbl20_ant0_rev3[] = {
0x00000000,
};
-const u32 tdi_tbl20_ant1_rev3[] = {
+static const u32 tdi_tbl20_ant1_rev3[] = {
0x00014b26,
0x00028d29,
0x000393ad,
@@ -7280,7 +7281,7 @@ const u32 tdi_tbl20_ant1_rev3[] = {
0x00000000,
};
-const u32 tdi_tbl40_ant0_rev3[] = {
+static const u32 tdi_tbl40_ant0_rev3[] = {
0x0011a346,
0x00136ccf,
0x0014f5d9,
@@ -7393,7 +7394,7 @@ const u32 tdi_tbl40_ant0_rev3[] = {
0x00000000,
};
-const u32 tdi_tbl40_ant1_rev3[] = {
+static const u32 tdi_tbl40_ant1_rev3[] = {
0x001edb36,
0x000129ca,
0x0002b353,
@@ -7506,7 +7507,7 @@ const u32 tdi_tbl40_ant1_rev3[] = {
0x00000000,
};
-const u32 pltlut_tbl_rev3[] = {
+static const u32 pltlut_tbl_rev3[] = {
0x76540213,
0x62407351,
0x76543210,
@@ -7515,7 +7516,7 @@ const u32 pltlut_tbl_rev3[] = {
0x76430521,
};
-const u32 chanest_tbl_rev3[] = {
+static const u32 chanest_tbl_rev3[] = {
0x44444444,
0x44444444,
0x44444444,
@@ -7614,7 +7615,7 @@ const u32 chanest_tbl_rev3[] = {
0x10101010,
};
-const u8 frame_lut_rev3[] = {
+static const u8 frame_lut_rev3[] = {
0x02,
0x04,
0x14,
@@ -7649,7 +7650,7 @@ const u8 frame_lut_rev3[] = {
0x2a,
};
-const u8 est_pwr_lut_core0_rev3[] = {
+static const u8 est_pwr_lut_core0_rev3[] = {
0x55,
0x54,
0x54,
@@ -7716,7 +7717,7 @@ const u8 est_pwr_lut_core0_rev3[] = {
0xfd,
};
-const u8 est_pwr_lut_core1_rev3[] = {
+static const u8 est_pwr_lut_core1_rev3[] = {
0x55,
0x54,
0x54,
@@ -7783,7 +7784,7 @@ const u8 est_pwr_lut_core1_rev3[] = {
0xfd,
};
-const u8 adj_pwr_lut_core0_rev3[] = {
+static const u8 adj_pwr_lut_core0_rev3[] = {
0x00,
0x00,
0x00,
@@ -7914,7 +7915,7 @@ const u8 adj_pwr_lut_core0_rev3[] = {
0x00,
};
-const u8 adj_pwr_lut_core1_rev3[] = {
+static const u8 adj_pwr_lut_core1_rev3[] = {
0x00,
0x00,
0x00,
@@ -8045,7 +8046,7 @@ const u8 adj_pwr_lut_core1_rev3[] = {
0x00,
};
-const u32 gainctrl_lut_core0_rev3[] = {
+static const u32 gainctrl_lut_core0_rev3[] = {
0x5bf70044,
0x5bf70042,
0x5bf70040,
@@ -8176,7 +8177,7 @@ const u32 gainctrl_lut_core0_rev3[] = {
0x5b07001c,
};
-const u32 gainctrl_lut_core1_rev3[] = {
+static const u32 gainctrl_lut_core1_rev3[] = {
0x5bf70044,
0x5bf70042,
0x5bf70040,
@@ -8307,7 +8308,7 @@ const u32 gainctrl_lut_core1_rev3[] = {
0x5b07001c,
};
-const u32 iq_lut_core0_rev3[] = {
+static const u32 iq_lut_core0_rev3[] = {
0x00000000,
0x00000000,
0x00000000,
@@ -8438,7 +8439,7 @@ const u32 iq_lut_core0_rev3[] = {
0x00000000,
};
-const u32 iq_lut_core1_rev3[] = {
+static const u32 iq_lut_core1_rev3[] = {
0x00000000,
0x00000000,
0x00000000,
@@ -8569,7 +8570,7 @@ const u32 iq_lut_core1_rev3[] = {
0x00000000,
};
-const u16 loft_lut_core0_rev3[] = {
+static const u16 loft_lut_core0_rev3[] = {
0x0000,
0x0000,
0x0000,
@@ -8700,7 +8701,7 @@ const u16 loft_lut_core0_rev3[] = {
0x0000,
};
-const u16 loft_lut_core1_rev3[] = {
+static const u16 loft_lut_core1_rev3[] = {
0x0000,
0x0000,
0x0000,
@@ -8831,7 +8832,7 @@ const u16 loft_lut_core1_rev3[] = {
0x0000,
};
-const u16 papd_comp_rfpwr_tbl_core0_rev3[] = {
+static const u16 papd_comp_rfpwr_tbl_core0_rev3[] = {
0x0036,
0x0036,
0x0036,
@@ -8962,7 +8963,7 @@ const u16 papd_comp_rfpwr_tbl_core0_rev3[] = {
0x01d6,
};
-const u16 papd_comp_rfpwr_tbl_core1_rev3[] = {
+static const u16 papd_comp_rfpwr_tbl_core1_rev3[] = {
0x0036,
0x0036,
0x0036,
@@ -9093,7 +9094,7 @@ const u16 papd_comp_rfpwr_tbl_core1_rev3[] = {
0x01d6,
};
-const u32 papd_comp_epsilon_tbl_core0_rev3[] = {
+static const u32 papd_comp_epsilon_tbl_core0_rev3[] = {
0x00000000,
0x00001fa0,
0x00019f78,
@@ -9160,7 +9161,7 @@ const u32 papd_comp_epsilon_tbl_core0_rev3[] = {
0x03e38ffe,
};
-const u32 papd_cal_scalars_tbl_core0_rev3[] = {
+static const u32 papd_cal_scalars_tbl_core0_rev3[] = {
0x05af005a,
0x0571005e,
0x05040066,
@@ -9227,7 +9228,7 @@ const u32 papd_cal_scalars_tbl_core0_rev3[] = {
0x002606a4,
};
-const u32 papd_comp_epsilon_tbl_core1_rev3[] = {
+static const u32 papd_comp_epsilon_tbl_core1_rev3[] = {
0x00000000,
0x00001fa0,
0x00019f78,
@@ -9294,7 +9295,7 @@ const u32 papd_comp_epsilon_tbl_core1_rev3[] = {
0x03e38ffe,
};
-const u32 papd_cal_scalars_tbl_core1_rev3[] = {
+static const u32 papd_cal_scalars_tbl_core1_rev3[] = {
0x05af005a,
0x0571005e,
0x05040066,
@@ -9489,7 +9490,7 @@ const u32 mimophytbl_info_sz_rev3_volatile3 =
sizeof(mimophytbl_info_rev3_volatile3) /
sizeof(mimophytbl_info_rev3_volatile3[0]);
-const u32 tmap_tbl_rev7[] = {
+static const u32 tmap_tbl_rev7[] = {
0x8a88aa80,
0x8aaaaa8a,
0x8a8a8aa8,
@@ -10199,7 +10200,7 @@ const u32 noise_var_tbl_rev7[] = {
0x0000014d,
};
-const u32 papd_comp_epsilon_tbl_core0_rev7[] = {
+static const u32 papd_comp_epsilon_tbl_core0_rev7[] = {
0x00000000,
0x00000000,
0x00016023,
@@ -10266,7 +10267,7 @@ const u32 papd_comp_epsilon_tbl_core0_rev7[] = {
0x0156cfff,
};
-const u32 papd_cal_scalars_tbl_core0_rev7[] = {
+static const u32 papd_cal_scalars_tbl_core0_rev7[] = {
0x0b5e002d,
0x0ae2002f,
0x0a3b0032,
@@ -10333,7 +10334,7 @@ const u32 papd_cal_scalars_tbl_core0_rev7[] = {
0x004e068c,
};
-const u32 papd_comp_epsilon_tbl_core1_rev7[] = {
+static const u32 papd_comp_epsilon_tbl_core1_rev7[] = {
0x00000000,
0x00000000,
0x00016023,
@@ -10400,7 +10401,7 @@ const u32 papd_comp_epsilon_tbl_core1_rev7[] = {
0x0156cfff,
};
-const u32 papd_cal_scalars_tbl_core1_rev7[] = {
+static const u32 papd_cal_scalars_tbl_core1_rev7[] = {
0x0b5e002d,
0x0ae2002f,
0x0a3b0032,
diff --git a/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.h b/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.h
index c5266cf23725..dc8a84e85117 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.h
+++ b/drivers/staging/brcm80211/brcmsmac/phy/phytbl_n.h
@@ -20,21 +20,31 @@
#include "phy_int.h"
extern const struct phytbl_info mimophytbl_info_rev0[],
- mimophytbl_info_rev0_volatile[];
-extern const u32 mimophytbl_info_sz_rev0, mimophytbl_info_sz_rev0_volatile;
+ mimophytbl_info_rev0_volatile[];
+
+extern const u32 mimophytbl_info_sz_rev0,
+ mimophytbl_info_sz_rev0_volatile;
extern const struct phytbl_info mimophytbl_info_rev3[],
- mimophytbl_info_rev3_volatile[], mimophytbl_info_rev3_volatile1[],
- mimophytbl_info_rev3_volatile2[], mimophytbl_info_rev3_volatile3[];
-extern const u32 mimophytbl_info_sz_rev3, mimophytbl_info_sz_rev3_volatile,
- mimophytbl_info_sz_rev3_volatile1, mimophytbl_info_sz_rev3_volatile2,
- mimophytbl_info_sz_rev3_volatile3;
+ mimophytbl_info_rev3_volatile[],
+ mimophytbl_info_rev3_volatile1[],
+ mimophytbl_info_rev3_volatile2[],
+ mimophytbl_info_rev3_volatile3[];
+
+extern const u32 mimophytbl_info_sz_rev3,
+ mimophytbl_info_sz_rev3_volatile,
+ mimophytbl_info_sz_rev3_volatile1,
+ mimophytbl_info_sz_rev3_volatile2,
+ mimophytbl_info_sz_rev3_volatile3;
extern const u32 noise_var_tbl_rev3[];
extern const struct phytbl_info mimophytbl_info_rev7[];
+
extern const u32 mimophytbl_info_sz_rev7;
+
extern const u32 noise_var_tbl_rev7[];
extern const struct phytbl_info mimophytbl_info_rev16[];
+
extern const u32 mimophytbl_info_sz_rev16;
diff --git a/drivers/staging/brcm80211/brcmsmac/phy_shim.c b/drivers/staging/brcm80211/brcmsmac/phy_shim.c
index 82ecdcda271f..5926854f62e2 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy_shim.c
+++ b/drivers/staging/brcm80211/brcmsmac/phy_shim.c
@@ -15,15 +15,15 @@
*/
/*
- * This is "two-way" interface, acting as the SHIM layer between WL and PHY layer.
- * WL driver can optinally call this translation layer to do some preprocessing, then reach PHY.
- * On the PHY->WL driver direction, all calls go through this layer since PHY doesn't have the
- * access to wlc_hw pointer.
+ * This is "two-way" interface, acting as the SHIM layer between driver
+ * and PHY layer. The driver can optionally call this translation layer
+ * to do some preprocessing, then reach PHY. On the PHY->driver direction,
+ * all calls go through this layer since PHY doesn't have access to the
+ * driver's brcms_hardware pointer.
*/
#include <linux/slab.h>
#include <net/mac80211.h>
-#include "bmac.h"
#include "main.h"
#include "mac80211_if.h"
#include "phy_shim.h"
@@ -31,21 +31,19 @@
/* PHY SHIM module specific state */
struct phy_shim_info {
struct brcms_hardware *wlc_hw; /* pointer to main wlc_hw structure */
- void *wlc; /* pointer to main wlc structure */
- void *wl; /* pointer to os-specific private state */
+ struct brcms_c_info *wlc; /* pointer to main wlc structure */
+ struct brcms_info *wl; /* pointer to os-specific private state */
};
struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw,
- void *wl, void *wlc) {
+ struct brcms_info *wl,
+ struct brcms_c_info *wlc) {
struct phy_shim_info *physhim = NULL;
physhim = kzalloc(sizeof(struct phy_shim_info), GFP_ATOMIC);
- if (!physhim) {
- wiphy_err(wlc_hw->wlc->wiphy,
- "wl%d: wlc_phy_shim_attach: out of mem\n",
- wlc_hw->unit);
+ if (!physhim)
return NULL;
- }
+
physhim->wlc_hw = wlc_hw;
physhim->wlc = wlc;
physhim->wl = wl;
@@ -59,28 +57,28 @@ void wlc_phy_shim_detach(struct phy_shim_info *physhim)
}
struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim,
- void (*fn) (void *arg), void *arg,
- const char *name)
+ void (*fn)(struct brcms_phy *pi),
+ void *arg, const char *name)
{
return (struct wlapi_timer *)
- brcms_init_timer(physhim->wl, fn, arg, name);
+ brcms_init_timer(physhim->wl, (void (*)(void *))fn,
+ arg, name);
}
-void wlapi_free_timer(struct phy_shim_info *physhim, struct wlapi_timer *t)
+void wlapi_free_timer(struct wlapi_timer *t)
{
- brcms_free_timer(physhim->wl, (struct brcms_timer *)t);
+ brcms_free_timer((struct brcms_timer *)t);
}
void
-wlapi_add_timer(struct phy_shim_info *physhim, struct wlapi_timer *t, uint ms,
- int periodic)
+wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic)
{
- brcms_add_timer(physhim->wl, (struct brcms_timer *)t, ms, periodic);
+ brcms_add_timer((struct brcms_timer *)t, ms, periodic);
}
-bool wlapi_del_timer(struct phy_shim_info *physhim, struct wlapi_timer *t)
+bool wlapi_del_timer(struct wlapi_timer *t)
{
- return brcms_del_timer(physhim->wl, (struct brcms_timer *)t);
+ return brcms_del_timer((struct brcms_timer *)t);
}
void wlapi_intrson(struct phy_shim_info *physhim)
@@ -216,3 +214,12 @@ wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf,
{
brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel);
}
+
+char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
+{
+ return getvar(physhim->wlc_hw->sih, id);
+}
+int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
+{
+ return getintvar(physhim->wlc_hw->sih, id);
+}
diff --git a/drivers/staging/brcm80211/brcmsmac/phy_shim.h b/drivers/staging/brcm80211/brcmsmac/phy_shim.h
index 2d12bb4400f1..9168c459b185 100644
--- a/drivers/staging/brcm80211/brcmsmac/phy_shim.h
+++ b/drivers/staging/brcm80211/brcmsmac/phy_shim.h
@@ -45,17 +45,17 @@
#define FRA_ERR_20MHZ 60
#define FRA_ERR_40MHZ 120
-#define ANTSEL_NA 0 /* No boardlevel selection available */
-#define ANTSEL_2x4 1 /* 2x4 boardlevel selection available */
-#define ANTSEL_2x3 2 /* 2x3 CB2 boardlevel selection available */
+#define ANTSEL_NA 0 /* No boardlevel selection available */
+#define ANTSEL_2x4 1 /* 2x4 boardlevel selection available */
+#define ANTSEL_2x3 2 /* 2x3 CB2 boardlevel selection available */
/* Rx Antenna diversity control values */
-#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */
-#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */
-#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */
-#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */
-#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */
-#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 /* default antdiv setting */
+#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */
+#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */
+#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */
+#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */
+#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */
+#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 /* default antdiv setting */
#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */
#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */
@@ -77,26 +77,40 @@
#define WL_TX_POWER_RATES 101
#define WL_TX_POWER_CCK_FIRST 0
#define WL_TX_POWER_CCK_NUM 4
-#define WL_TX_POWER_OFDM_FIRST 4 /* Index for first 20MHz OFDM SISO rate */
-#define WL_TX_POWER_OFDM20_CDD_FIRST 12 /* Index for first 20MHz OFDM CDD rate */
-#define WL_TX_POWER_OFDM40_SISO_FIRST 52 /* Index for first 40MHz OFDM SISO rate */
-#define WL_TX_POWER_OFDM40_CDD_FIRST 60 /* Index for first 40MHz OFDM CDD rate */
+/* Index for first 20MHz OFDM SISO rate */
+#define WL_TX_POWER_OFDM_FIRST 4
+/* Index for first 20MHz OFDM CDD rate */
+#define WL_TX_POWER_OFDM20_CDD_FIRST 12
+/* Index for first 40MHz OFDM SISO rate */
+#define WL_TX_POWER_OFDM40_SISO_FIRST 52
+/* Index for first 40MHz OFDM CDD rate */
+#define WL_TX_POWER_OFDM40_CDD_FIRST 60
#define WL_TX_POWER_OFDM_NUM 8
-#define WL_TX_POWER_MCS20_SISO_FIRST 20 /* Index for first 20MHz MCS SISO rate */
-#define WL_TX_POWER_MCS20_CDD_FIRST 28 /* Index for first 20MHz MCS CDD rate */
-#define WL_TX_POWER_MCS20_STBC_FIRST 36 /* Index for first 20MHz MCS STBC rate */
-#define WL_TX_POWER_MCS20_SDM_FIRST 44 /* Index for first 20MHz MCS SDM rate */
-#define WL_TX_POWER_MCS40_SISO_FIRST 68 /* Index for first 40MHz MCS SISO rate */
-#define WL_TX_POWER_MCS40_CDD_FIRST 76 /* Index for first 40MHz MCS CDD rate */
-#define WL_TX_POWER_MCS40_STBC_FIRST 84 /* Index for first 40MHz MCS STBC rate */
-#define WL_TX_POWER_MCS40_SDM_FIRST 92 /* Index for first 40MHz MCS SDM rate */
+/* Index for first 20MHz MCS SISO rate */
+#define WL_TX_POWER_MCS20_SISO_FIRST 20
+/* Index for first 20MHz MCS CDD rate */
+#define WL_TX_POWER_MCS20_CDD_FIRST 28
+/* Index for first 20MHz MCS STBC rate */
+#define WL_TX_POWER_MCS20_STBC_FIRST 36
+/* Index for first 20MHz MCS SDM rate */
+#define WL_TX_POWER_MCS20_SDM_FIRST 44
+/* Index for first 40MHz MCS SISO rate */
+#define WL_TX_POWER_MCS40_SISO_FIRST 68
+/* Index for first 40MHz MCS CDD rate */
+#define WL_TX_POWER_MCS40_CDD_FIRST 76
+/* Index for first 40MHz MCS STBC rate */
+#define WL_TX_POWER_MCS40_STBC_FIRST 84
+/* Index for first 40MHz MCS SDM rate */
+#define WL_TX_POWER_MCS40_SDM_FIRST 92
#define WL_TX_POWER_MCS_1_STREAM_NUM 8
#define WL_TX_POWER_MCS_2_STREAM_NUM 8
-#define WL_TX_POWER_MCS_32 100 /* Index for 40MHz rate MCS 32 */
+/* Index for 40MHz rate MCS 32 */
+#define WL_TX_POWER_MCS_32 100
#define WL_TX_POWER_MCS_32_NUM 1
/* sslpnphy specifics */
-#define WL_TX_POWER_MCS20_SISO_FIRST_SSN 12 /* Index for first 20MHz MCS SISO rate */
+/* Index for first 20MHz MCS SISO rate */
+#define WL_TX_POWER_MCS20_SISO_FIRST_SSN 12
/* struct tx_power::flags bits */
#define WL_TX_POWER_F_ENABLED 1
@@ -108,20 +122,20 @@
#define BRCMS_N_TXRX_CHAIN0 0
#define BRCMS_N_TXRX_CHAIN1 1
+struct brcms_phy;
+
extern struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw,
- void *wl, void *wlc);
+ struct brcms_info *wl,
+ struct brcms_c_info *wlc);
extern void wlc_phy_shim_detach(struct phy_shim_info *physhim);
/* PHY to WL utility functions */
extern struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim,
- void (*fn) (void *arg), void *arg,
- const char *name);
-extern void wlapi_free_timer(struct phy_shim_info *physhim,
- struct wlapi_timer *t);
-extern void wlapi_add_timer(struct phy_shim_info *physhim,
- struct wlapi_timer *t, uint ms, int periodic);
-extern bool wlapi_del_timer(struct phy_shim_info *physhim,
- struct wlapi_timer *t);
+ void (*fn) (struct brcms_phy *pi),
+ void *arg, const char *name);
+extern void wlapi_free_timer(struct wlapi_timer *t);
+extern void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic);
+extern bool wlapi_del_timer(struct wlapi_timer *t);
extern void wlapi_intrson(struct phy_shim_info *physhim);
extern u32 wlapi_intrsoff(struct phy_shim_info *physhim);
extern void wlapi_intrsrestore(struct phy_shim_info *physhim,
@@ -161,4 +175,8 @@ extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint,
extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim,
u32 phy_mode);
extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim);
+extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id);
+extern int wlapi_getintvar(struct phy_shim_info *physhim,
+ enum brcms_srom_id id);
+
#endif /* _BRCM_PHY_SHIM_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/pmu.c b/drivers/staging/brcm80211/brcmsmac/pmu.c
index e8b2b81d2d04..3b36e3acfd74 100644
--- a/drivers/staging/brcm80211/brcmsmac/pmu.c
+++ b/drivers/staging/brcm80211/brcmsmac/pmu.c
@@ -70,11 +70,13 @@
#define PMURES_BIT(bit) (1 << (bit))
/* PMU corerev and chip specific PLL controls.
- * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary number
- * to differentiate different PLLs controlled by the same PMU rev.
+ * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary
+ * number to differentiate different PLLs controlled by the same PMU rev.
+ */
+/* pllcontrol registers:
+ * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>,
+ * p1div, p2div, _bypass_sdmod
*/
-/* pllcontrol registers */
-/* ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, p1div, p2div, _bypass_sdmod */
#define PMU1_PLL0_PLLCTL0 0
#define PMU1_PLL0_PLLCTL1 1
#define PMU1_PLL0_PLLCTL2 2
@@ -137,7 +139,8 @@ static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax)
}
static void
-si_pmu_spuravoid_pllupdate(struct si_pub *sih, chipcregs_t *cc, u8 spuravoid)
+si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc,
+ u8 spuravoid)
{
u32 tmp = 0;
@@ -199,28 +202,6 @@ si_pmu_spuravoid_pllupdate(struct si_pub *sih, chipcregs_t *cc, u8 spuravoid)
W_REG(&cc->pmucontrol, tmp);
}
-u32 si_pmu_ilp_clock(struct si_pub *sih)
-{
- static u32 ilpcycles_per_sec;
-
- if (!PMUCTL_ENAB(sih))
- return ILP_CLOCK;
-
- if (ilpcycles_per_sec == 0) {
- u32 start, end, delta;
- u32 origidx = ai_coreidx(sih);
- chipcregs_t *cc = ai_setcoreidx(sih, SI_CC_IDX);
- start = R_REG(&cc->pmutimer);
- mdelay(ILP_CALC_DUR);
- end = R_REG(&cc->pmutimer);
- delta = end - start;
- ilpcycles_per_sec = delta * (1000 / ILP_CALC_DUR);
- ai_setcoreidx(sih, origidx);
- }
-
- return ilpcycles_per_sec;
-}
-
u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
{
uint delay = PMU_MAX_TRANSITION_DLY;
@@ -240,7 +221,7 @@ u16 si_pmu_fast_pwrup_delay(struct si_pub *sih)
void si_pmu_sprom_enable(struct si_pub *sih, bool enable)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
/* Remember original core before switch to chipc */
@@ -254,34 +235,37 @@ void si_pmu_sprom_enable(struct si_pub *sih, bool enable)
/* Read/write a chipcontrol reg */
u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
{
- ai_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, chipcontrol_addr), ~0,
- reg);
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol_addr),
+ ~0, reg);
return ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, chipcontrol_data), mask, val);
+ offsetof(struct chipcregs, chipcontrol_data), mask,
+ val);
}
/* Read/write a regcontrol reg */
u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
{
- ai_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, regcontrol_addr), ~0,
- reg);
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, regcontrol_addr),
+ ~0, reg);
return ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, regcontrol_data), mask, val);
+ offsetof(struct chipcregs, regcontrol_data), mask,
+ val);
}
/* Read/write a pllcontrol reg */
u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val)
{
- ai_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, pllcontrol_addr), ~0,
- reg);
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pllcontrol_addr),
+ ~0, reg);
return ai_corereg(sih, SI_CC_IDX,
- offsetof(chipcregs_t, pllcontrol_data), mask, val);
+ offsetof(struct chipcregs, pllcontrol_data), mask,
+ val);
}
/* PMU PLL update */
void si_pmu_pllupd(struct si_pub *sih)
{
- ai_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, pmucontrol),
+ ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol),
PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD);
}
@@ -291,7 +275,7 @@ u32 si_pmu_alp_clock(struct si_pub *sih)
u32 clock = ALP_CLOCK;
/* bail out with default */
- if (!PMUCTL_ENAB(sih))
+ if (!(sih->cccaps & CC_CAP_PMU))
return clock;
switch (sih->chip) {
@@ -310,12 +294,12 @@ u32 si_pmu_alp_clock(struct si_pub *sih)
void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx, intr_val;
/* Remember original core before switch to chipc */
- cc = (chipcregs_t *) ai_switch_core(sih, CC_CORE_ID, &origidx,
- &intr_val);
+ cc = (struct chipcregs __iomem *)
+ ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
/* update the pll changes */
si_pmu_spuravoid_pllupdate(sih, cc, spuravoid);
@@ -327,7 +311,7 @@ void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid)
/* initialize PMU */
void si_pmu_init(struct si_pub *sih)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
/* Remember original core before switch to chipc */
@@ -366,7 +350,7 @@ void si_pmu_swreg_init(struct si_pub *sih)
/* initialize PLL */
void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
/* Remember original core before switch to chipc */
@@ -390,7 +374,7 @@ void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq)
/* initialize PMU resources */
void si_pmu_res_init(struct si_pub *sih)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
u32 min_mask = 0, max_mask = 0;
@@ -422,7 +406,7 @@ void si_pmu_res_init(struct si_pub *sih)
u32 si_pmu_measure_alpclk(struct si_pub *sih)
{
- chipcregs_t *cc;
+ struct chipcregs __iomem *cc;
uint origidx;
u32 alp_khz;
diff --git a/drivers/staging/brcm80211/brcmsmac/pmu.h b/drivers/staging/brcm80211/brcmsmac/pmu.h
index 0c7e48c4bcd8..3a08c620640e 100644
--- a/drivers/staging/brcm80211/brcmsmac/pmu.h
+++ b/drivers/staging/brcm80211/brcmsmac/pmu.h
@@ -19,25 +19,11 @@
#define _BRCM_PMU_H_
#include "types.h"
-/*
- * LDO selections used in si_pmu_set_ldo_voltage
- */
-#define SET_LDO_VOLTAGE_LDO1 1
-#define SET_LDO_VOLTAGE_LDO2 2
-#define SET_LDO_VOLTAGE_LDO3 3
-#define SET_LDO_VOLTAGE_PAREF 4
-#define SET_LDO_VOLTAGE_CLDO_PWM 5
-#define SET_LDO_VOLTAGE_CLDO_BURST 6
-#define SET_LDO_VOLTAGE_CBUCK_PWM 7
-#define SET_LDO_VOLTAGE_CBUCK_BURST 8
-#define SET_LDO_VOLTAGE_LNLDO1 9
-#define SET_LDO_VOLTAGE_LNLDO2_SEL 10
extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih);
extern void si_pmu_sprom_enable(struct si_pub *sih, bool enable);
extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val);
-extern u32 si_pmu_ilp_clock(struct si_pub *sih);
extern u32 si_pmu_alp_clock(struct si_pub *sih);
extern void si_pmu_pllupd(struct si_pub *sih);
extern void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid);
diff --git a/drivers/staging/brcm80211/brcmsmac/pub.h b/drivers/staging/brcm80211/brcmsmac/pub.h
index 01d74609560f..37bb2dcc113f 100644
--- a/drivers/staging/brcm80211/brcmsmac/pub.h
+++ b/drivers/staging/brcm80211/brcmsmac/pub.h
@@ -21,8 +21,265 @@
#include "types.h"
#include "defs.h"
+enum brcms_srom_id {
+ BRCMS_SROM_NULL,
+ BRCMS_SROM_CONT,
+ BRCMS_SROM_AA2G,
+ BRCMS_SROM_AA5G,
+ BRCMS_SROM_AG0,
+ BRCMS_SROM_AG1,
+ BRCMS_SROM_AG2,
+ BRCMS_SROM_AG3,
+ BRCMS_SROM_ANTSWCTL2G,
+ BRCMS_SROM_ANTSWCTL5G,
+ BRCMS_SROM_ANTSWITCH,
+ BRCMS_SROM_BOARDFLAGS2,
+ BRCMS_SROM_BOARDFLAGS,
+ BRCMS_SROM_BOARDNUM,
+ BRCMS_SROM_BOARDREV,
+ BRCMS_SROM_BOARDTYPE,
+ BRCMS_SROM_BW40PO,
+ BRCMS_SROM_BWDUPPO,
+ BRCMS_SROM_BXA2G,
+ BRCMS_SROM_BXA5G,
+ BRCMS_SROM_CC,
+ BRCMS_SROM_CCK2GPO,
+ BRCMS_SROM_CCKBW202GPO,
+ BRCMS_SROM_CCKBW20UL2GPO,
+ BRCMS_SROM_CCODE,
+ BRCMS_SROM_CDDPO,
+ BRCMS_SROM_DEVID,
+ BRCMS_SROM_ET1MACADDR,
+ BRCMS_SROM_EXTPAGAIN2G,
+ BRCMS_SROM_EXTPAGAIN5G,
+ BRCMS_SROM_FREQOFFSET_CORR,
+ BRCMS_SROM_HW_IQCAL_EN,
+ BRCMS_SROM_IL0MACADDR,
+ BRCMS_SROM_IQCAL_SWP_DIS,
+ BRCMS_SROM_LEDBH0,
+ BRCMS_SROM_LEDBH1,
+ BRCMS_SROM_LEDBH2,
+ BRCMS_SROM_LEDBH3,
+ BRCMS_SROM_LEDDC,
+ BRCMS_SROM_LEGOFDM40DUPPO,
+ BRCMS_SROM_LEGOFDMBW202GPO,
+ BRCMS_SROM_LEGOFDMBW205GHPO,
+ BRCMS_SROM_LEGOFDMBW205GLPO,
+ BRCMS_SROM_LEGOFDMBW205GMPO,
+ BRCMS_SROM_LEGOFDMBW20UL2GPO,
+ BRCMS_SROM_LEGOFDMBW20UL5GHPO,
+ BRCMS_SROM_LEGOFDMBW20UL5GLPO,
+ BRCMS_SROM_LEGOFDMBW20UL5GMPO,
+ BRCMS_SROM_MACADDR,
+ BRCMS_SROM_MCS2GPO0,
+ BRCMS_SROM_MCS2GPO1,
+ BRCMS_SROM_MCS2GPO2,
+ BRCMS_SROM_MCS2GPO3,
+ BRCMS_SROM_MCS2GPO4,
+ BRCMS_SROM_MCS2GPO5,
+ BRCMS_SROM_MCS2GPO6,
+ BRCMS_SROM_MCS2GPO7,
+ BRCMS_SROM_MCS32PO,
+ BRCMS_SROM_MCS5GHPO0,
+ BRCMS_SROM_MCS5GHPO1,
+ BRCMS_SROM_MCS5GHPO2,
+ BRCMS_SROM_MCS5GHPO3,
+ BRCMS_SROM_MCS5GHPO4,
+ BRCMS_SROM_MCS5GHPO5,
+ BRCMS_SROM_MCS5GHPO6,
+ BRCMS_SROM_MCS5GHPO7,
+ BRCMS_SROM_MCS5GLPO0,
+ BRCMS_SROM_MCS5GLPO1,
+ BRCMS_SROM_MCS5GLPO2,
+ BRCMS_SROM_MCS5GLPO3,
+ BRCMS_SROM_MCS5GLPO4,
+ BRCMS_SROM_MCS5GLPO5,
+ BRCMS_SROM_MCS5GLPO6,
+ BRCMS_SROM_MCS5GLPO7,
+ BRCMS_SROM_MCS5GPO0,
+ BRCMS_SROM_MCS5GPO1,
+ BRCMS_SROM_MCS5GPO2,
+ BRCMS_SROM_MCS5GPO3,
+ BRCMS_SROM_MCS5GPO4,
+ BRCMS_SROM_MCS5GPO5,
+ BRCMS_SROM_MCS5GPO6,
+ BRCMS_SROM_MCS5GPO7,
+ BRCMS_SROM_MCSBW202GPO,
+ BRCMS_SROM_MCSBW205GHPO,
+ BRCMS_SROM_MCSBW205GLPO,
+ BRCMS_SROM_MCSBW205GMPO,
+ BRCMS_SROM_MCSBW20UL2GPO,
+ BRCMS_SROM_MCSBW20UL5GHPO,
+ BRCMS_SROM_MCSBW20UL5GLPO,
+ BRCMS_SROM_MCSBW20UL5GMPO,
+ BRCMS_SROM_MCSBW402GPO,
+ BRCMS_SROM_MCSBW405GHPO,
+ BRCMS_SROM_MCSBW405GLPO,
+ BRCMS_SROM_MCSBW405GMPO,
+ BRCMS_SROM_MEASPOWER,
+ BRCMS_SROM_OFDM2GPO,
+ BRCMS_SROM_OFDM5GHPO,
+ BRCMS_SROM_OFDM5GLPO,
+ BRCMS_SROM_OFDM5GPO,
+ BRCMS_SROM_OPO,
+ BRCMS_SROM_PA0B0,
+ BRCMS_SROM_PA0B1,
+ BRCMS_SROM_PA0B2,
+ BRCMS_SROM_PA0ITSSIT,
+ BRCMS_SROM_PA0MAXPWR,
+ BRCMS_SROM_PA1B0,
+ BRCMS_SROM_PA1B1,
+ BRCMS_SROM_PA1B2,
+ BRCMS_SROM_PA1HIB0,
+ BRCMS_SROM_PA1HIB1,
+ BRCMS_SROM_PA1HIB2,
+ BRCMS_SROM_PA1HIMAXPWR,
+ BRCMS_SROM_PA1ITSSIT,
+ BRCMS_SROM_PA1LOB0,
+ BRCMS_SROM_PA1LOB1,
+ BRCMS_SROM_PA1LOB2,
+ BRCMS_SROM_PA1LOMAXPWR,
+ BRCMS_SROM_PA1MAXPWR,
+ BRCMS_SROM_PDETRANGE2G,
+ BRCMS_SROM_PDETRANGE5G,
+ BRCMS_SROM_PHYCAL_TEMPDELTA,
+ BRCMS_SROM_RAWTEMPSENSE,
+ BRCMS_SROM_REGREV,
+ BRCMS_SROM_REV,
+ BRCMS_SROM_RSSISAV2G,
+ BRCMS_SROM_RSSISAV5G,
+ BRCMS_SROM_RSSISMC2G,
+ BRCMS_SROM_RSSISMC5G,
+ BRCMS_SROM_RSSISMF2G,
+ BRCMS_SROM_RSSISMF5G,
+ BRCMS_SROM_RXCHAIN,
+ BRCMS_SROM_RXPO2G,
+ BRCMS_SROM_RXPO5G,
+ BRCMS_SROM_STBCPO,
+ BRCMS_SROM_TEMPCORRX,
+ BRCMS_SROM_TEMPOFFSET,
+ BRCMS_SROM_TEMPSENSE_OPTION,
+ BRCMS_SROM_TEMPSENSE_SLOPE,
+ BRCMS_SROM_TEMPTHRESH,
+ BRCMS_SROM_TRI2G,
+ BRCMS_SROM_TRI5GH,
+ BRCMS_SROM_TRI5GL,
+ BRCMS_SROM_TRI5G,
+ BRCMS_SROM_TRISO2G,
+ BRCMS_SROM_TRISO5G,
+ BRCMS_SROM_TSSIPOS2G,
+ BRCMS_SROM_TSSIPOS5G,
+ BRCMS_SROM_TXCHAIN,
+ BRCMS_SROM_TXPID2GA0,
+ BRCMS_SROM_TXPID2GA1,
+ BRCMS_SROM_TXPID2GA2,
+ BRCMS_SROM_TXPID2GA3,
+ BRCMS_SROM_TXPID5GA0,
+ BRCMS_SROM_TXPID5GA1,
+ BRCMS_SROM_TXPID5GA2,
+ BRCMS_SROM_TXPID5GA3,
+ BRCMS_SROM_TXPID5GHA0,
+ BRCMS_SROM_TXPID5GHA1,
+ BRCMS_SROM_TXPID5GHA2,
+ BRCMS_SROM_TXPID5GHA3,
+ BRCMS_SROM_TXPID5GLA0,
+ BRCMS_SROM_TXPID5GLA1,
+ BRCMS_SROM_TXPID5GLA2,
+ BRCMS_SROM_TXPID5GLA3,
+ /*
+ * per-path identifiers (see srom.c)
+ */
+ BRCMS_SROM_ITT2GA0,
+ BRCMS_SROM_ITT2GA1,
+ BRCMS_SROM_ITT2GA2,
+ BRCMS_SROM_ITT2GA3,
+ BRCMS_SROM_ITT5GA0,
+ BRCMS_SROM_ITT5GA1,
+ BRCMS_SROM_ITT5GA2,
+ BRCMS_SROM_ITT5GA3,
+ BRCMS_SROM_MAXP2GA0,
+ BRCMS_SROM_MAXP2GA1,
+ BRCMS_SROM_MAXP2GA2,
+ BRCMS_SROM_MAXP2GA3,
+ BRCMS_SROM_MAXP5GA0,
+ BRCMS_SROM_MAXP5GA1,
+ BRCMS_SROM_MAXP5GA2,
+ BRCMS_SROM_MAXP5GA3,
+ BRCMS_SROM_MAXP5GHA0,
+ BRCMS_SROM_MAXP5GHA1,
+ BRCMS_SROM_MAXP5GHA2,
+ BRCMS_SROM_MAXP5GHA3,
+ BRCMS_SROM_MAXP5GLA0,
+ BRCMS_SROM_MAXP5GLA1,
+ BRCMS_SROM_MAXP5GLA2,
+ BRCMS_SROM_MAXP5GLA3,
+ BRCMS_SROM_PA2GW0A0,
+ BRCMS_SROM_PA2GW0A1,
+ BRCMS_SROM_PA2GW0A2,
+ BRCMS_SROM_PA2GW0A3,
+ BRCMS_SROM_PA2GW1A0,
+ BRCMS_SROM_PA2GW1A1,
+ BRCMS_SROM_PA2GW1A2,
+ BRCMS_SROM_PA2GW1A3,
+ BRCMS_SROM_PA2GW2A0,
+ BRCMS_SROM_PA2GW2A1,
+ BRCMS_SROM_PA2GW2A2,
+ BRCMS_SROM_PA2GW2A3,
+ BRCMS_SROM_PA2GW3A0,
+ BRCMS_SROM_PA2GW3A1,
+ BRCMS_SROM_PA2GW3A2,
+ BRCMS_SROM_PA2GW3A3,
+ BRCMS_SROM_PA5GHW0A0,
+ BRCMS_SROM_PA5GHW0A1,
+ BRCMS_SROM_PA5GHW0A2,
+ BRCMS_SROM_PA5GHW0A3,
+ BRCMS_SROM_PA5GHW1A0,
+ BRCMS_SROM_PA5GHW1A1,
+ BRCMS_SROM_PA5GHW1A2,
+ BRCMS_SROM_PA5GHW1A3,
+ BRCMS_SROM_PA5GHW2A0,
+ BRCMS_SROM_PA5GHW2A1,
+ BRCMS_SROM_PA5GHW2A2,
+ BRCMS_SROM_PA5GHW2A3,
+ BRCMS_SROM_PA5GHW3A0,
+ BRCMS_SROM_PA5GHW3A1,
+ BRCMS_SROM_PA5GHW3A2,
+ BRCMS_SROM_PA5GHW3A3,
+ BRCMS_SROM_PA5GLW0A0,
+ BRCMS_SROM_PA5GLW0A1,
+ BRCMS_SROM_PA5GLW0A2,
+ BRCMS_SROM_PA5GLW0A3,
+ BRCMS_SROM_PA5GLW1A0,
+ BRCMS_SROM_PA5GLW1A1,
+ BRCMS_SROM_PA5GLW1A2,
+ BRCMS_SROM_PA5GLW1A3,
+ BRCMS_SROM_PA5GLW2A0,
+ BRCMS_SROM_PA5GLW2A1,
+ BRCMS_SROM_PA5GLW2A2,
+ BRCMS_SROM_PA5GLW2A3,
+ BRCMS_SROM_PA5GLW3A0,
+ BRCMS_SROM_PA5GLW3A1,
+ BRCMS_SROM_PA5GLW3A2,
+ BRCMS_SROM_PA5GLW3A3,
+ BRCMS_SROM_PA5GW0A0,
+ BRCMS_SROM_PA5GW0A1,
+ BRCMS_SROM_PA5GW0A2,
+ BRCMS_SROM_PA5GW0A3,
+ BRCMS_SROM_PA5GW1A0,
+ BRCMS_SROM_PA5GW1A1,
+ BRCMS_SROM_PA5GW1A2,
+ BRCMS_SROM_PA5GW1A3,
+ BRCMS_SROM_PA5GW2A0,
+ BRCMS_SROM_PA5GW2A1,
+ BRCMS_SROM_PA5GW2A2,
+ BRCMS_SROM_PA5GW2A3,
+ BRCMS_SROM_PA5GW3A0,
+ BRCMS_SROM_PA5GW3A1,
+ BRCMS_SROM_PA5GW3A2,
+ BRCMS_SROM_PA5GW3A3,
+};
+
#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */
-#define MAXMULTILIST 32 /* max # multicast addresses */
#define D11_PHY_HDR_LEN 6 /* Phy header length - 6 bytes */
/* phy types */
@@ -40,10 +297,6 @@
#define BRCMS_20_MHZ 20 /* 20Mhz nphy channel bandwidth */
#define BRCMS_40_MHZ 40 /* 40Mhz nphy channel bandwidth */
-#define CHSPEC_WLC_BW(chanspec) (CHSPEC_IS40(chanspec) ? BRCMS_40_MHZ : \
- CHSPEC_IS20(chanspec) ? BRCMS_20_MHZ : \
- BRCMS_10_MHZ)
-
#define BRCMS_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */
#define BRCMS_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */
#define BRCMS_RSSI_VERY_LOW -80 /* Very low quality cutoffs */
@@ -52,13 +305,6 @@
#define BRCMS_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */
#define BRCMS_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */
-/* macro to perform PHY -> D11 PHY TYPE, currently 1:1 */
-#define BRCMS_PHYTYPE(_x) (_x)
-
-#define MA_WINDOW_SZ 8 /* moving average window size */
-
-#define BRCMS_SNR_INVALID 0 /* invalid SNR value */
-
/* a large TX Power as an init value to factor out of min() calculations,
* keep low enough to fit in an s8, units are .25 dBm
*/
@@ -69,63 +315,58 @@
#define BRCMS_RATE_MASK 0x7f /* Rate value mask w/o basic rate flag */
/* legacy rx Antenna diversity for SISO rates */
-#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */
-#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */
-#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */
-#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */
-#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */
-#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 /* default antdiv setting */
+#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */
+#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */
+#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */
+#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */
+#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */
+/* default antdiv setting */
+#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0
/* legacy rx Antenna diversity for SISO rates */
-#define ANT_TX_FORCE_0 0 /* Tx on antenna 0, "legacy term Main" */
-#define ANT_TX_FORCE_1 1 /* Tx on antenna 1, "legacy term Aux" */
-#define ANT_TX_LAST_RX 3 /* Tx on phy's last good Rx antenna */
-#define ANT_TX_DEF 3 /* driver's default tx antenna setting */
-
-#define TXCORE_POLICY_ALL 0x1 /* use all available core for transmit */
+/* Tx on antenna 0, "legacy term Main" */
+#define ANT_TX_FORCE_0 0
+/* Tx on antenna 1, "legacy term Aux" */
+#define ANT_TX_FORCE_1 1
+/* Tx on phy's last good Rx antenna */
+#define ANT_TX_LAST_RX 3
+/* driver's default tx antenna setting */
+#define ANT_TX_DEF 3
/* Tx Chain values */
-#define TXCHAIN_DEF 0x1 /* def bitmap of txchain */
-#define TXCHAIN_DEF_NPHY 0x3 /* default bitmap of tx chains for nphy */
-#define TXCHAIN_DEF_HTPHY 0x7 /* default bitmap of tx chains for nphy */
-#define RXCHAIN_DEF 0x1 /* def bitmap of rxchain */
-#define RXCHAIN_DEF_NPHY 0x3 /* default bitmap of rx chains for nphy */
-#define RXCHAIN_DEF_HTPHY 0x7 /* default bitmap of rx chains for nphy */
-#define ANTSWITCH_NONE 0 /* no antenna switch */
-#define ANTSWITCH_TYPE_1 1 /* antenna switch on 4321CB2, 2of3 */
-#define ANTSWITCH_TYPE_2 2 /* antenna switch on 4321MPCI, 2of3 */
-#define ANTSWITCH_TYPE_3 3 /* antenna switch on 4322, 2of3 */
+/* def bitmap of txchain */
+#define TXCHAIN_DEF 0x1
+/* default bitmap of tx chains for nphy */
+#define TXCHAIN_DEF_NPHY 0x3
+/* default bitmap of tx chains for nphy */
+#define TXCHAIN_DEF_HTPHY 0x7
+/* def bitmap of rxchain */
+#define RXCHAIN_DEF 0x1
+/* default bitmap of rx chains for nphy */
+#define RXCHAIN_DEF_NPHY 0x3
+/* default bitmap of rx chains for nphy */
+#define RXCHAIN_DEF_HTPHY 0x7
+/* no antenna switch */
+#define ANTSWITCH_NONE 0
+/* antenna switch on 4321CB2, 2of3 */
+#define ANTSWITCH_TYPE_1 1
+/* antenna switch on 4321MPCI, 2of3 */
+#define ANTSWITCH_TYPE_2 2
+/* antenna switch on 4322, 2of3 */
+#define ANTSWITCH_TYPE_3 3
#define RXBUFSZ PKTBUFSZ
-#ifndef AIDMAPSZ
-#define AIDMAPSZ (roundup(MAXSCB, NBBY)/NBBY) /* aid bitmap size in bytes */
-#endif /* AIDMAPSZ */
#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */
-#define WL_SPURAVOID_OFF 0
-#define WL_SPURAVOID_ON1 1
-#define WL_SPURAVOID_ON2 2
-
-struct brcms_tunables {
- int ntxd; /* size of tx descriptor table */
- int nrxd; /* size of rx descriptor table */
- int rxbufsz; /* size of rx buffers to post */
- int nrxbufpost; /* # of rx buffers to post */
- int maxscb; /* # of SCBs supported */
- int ampdunummpdu; /* max number of mpdu in an ampdu */
- int maxpktcb; /* max # of packet callbacks */
- int maxucodebss; /* max # of BSS handled in ucode bcn/prb */
- int maxucodebss4; /* max # of BSS handled in sw bcn/prb */
- int maxbss; /* max # of bss info elements in scan list */
- int datahiwat; /* data msg txq hiwat mark */
- int ampdudatahiwat; /* AMPDU msg txq hiwat mark */
- int rxbnd; /* max # of rx bufs to process before deferring to dpc */
- int txsbnd; /* max # tx status to process in wlc_txstatus() */
- int memreserved; /* memory reserved for BMAC's USB dma rx */
+struct brcm_rateset {
+ /* # rates in this set */
+ u32 count;
+ /* rates in 500kbps units w/hi bit set if basic */
+ u8 rates[WL_NUMRATES];
};
-struct brcms_rateset {
+struct brcms_c_rateset {
uint count; /* number of rates in rates[] */
/* rates in 500kbps units w/hi bit set if basic */
u8 rates[BRCMS_NUMRATES];
@@ -133,34 +374,11 @@ struct brcms_rateset {
u8 mcs[MCSSET_LEN]; /* supported mcs index bit map */
};
-struct rsn_parms {
- u8 flags; /* misc booleans (e.g., supported) */
- u8 multicast; /* multicast cipher */
- u8 ucount; /* count of unicast ciphers */
- u8 unicast[4]; /* unicast ciphers */
- u8 acount; /* count of auth modes */
- u8 auth[4]; /* Authentication modes */
- u8 PAD[4]; /* padding for future growth */
-};
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1)
-
-#define RSN_FLAGS_SUPPORTED 0x1 /* Flag for rsn_params */
-#define RSN_FLAGS_PREAUTH 0x2 /* Flag for WPA2 rsn_params */
-
/* All the HT-specific default advertised capabilities (including AMPDU)
* should be grouped here at one place
*/
#define AMPDU_DEF_MPDU_DENSITY 6 /* default mpdu density (110 ==> 4us) */
-/* defaults for the HT (MIMO) bss */
-#define HT_CAP (IEEE80211_HT_CAP_SM_PS |\
- IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_GRN_FLD |\
- IEEE80211_HT_CAP_MAX_AMSDU | IEEE80211_HT_CAP_DSSSCCK40)
-
/* wlc internal bss_info */
struct brcms_bss_info {
u8 BSSID[ETH_ALEN]; /* network BSSID */
@@ -170,200 +388,55 @@ struct brcms_bss_info {
s16 RSSI; /* receive signal strength (in dBm) */
s16 SNR; /* receive signal SNR in dB */
u16 beacon_period; /* units are Kusec */
- u16 atim_window; /* units are Kusec */
- chanspec_t chanspec; /* Channel num, bw, ctrl_sb and band */
- s8 infra; /* 0=IBSS, 1=infrastructure, 2=unknown */
- wlc_rateset_t rateset; /* supported rates */
- u8 dtim_period; /* DTIM period */
- s8 phy_noise; /* noise right after tx (in dBm) */
- u16 capability; /* Capability information */
- u8 wme_qosinfo; /* QoS Info from WME IE; valid if BSS_WME flag set */
- struct rsn_parms wpa;
- struct rsn_parms wpa2;
- u16 qbss_load_aac; /* qbss load available admission capacity */
- /* qbss_load_chan_free <- (0xff - channel_utilization of qbss_load_ie_t) */
- u8 qbss_load_chan_free; /* indicates how free the channel is */
- u8 mcipher; /* multicast cipher */
- u8 wpacfg; /* wpa config index */
+ u16 chanspec; /* Channel num, bw, ctrl_sb and band */
+ struct brcms_c_rateset rateset; /* supported rates */
};
-/* IOVar flags for common error checks */
-#define IOVF_MFG (1<<3) /* flag for mfgtest iovars */
-#define IOVF_WHL (1<<4) /* value must be whole (0-max) */
-#define IOVF_NTRL (1<<5) /* value must be natural (1-max) */
-
-#define IOVF_SET_UP (1<<6) /* set requires driver be up */
-#define IOVF_SET_DOWN (1<<7) /* set requires driver be down */
-#define IOVF_SET_CLK (1<<8) /* set requires core clock */
-#define IOVF_SET_BAND (1<<9) /* set requires fixed band */
-
-#define IOVF_GET_UP (1<<10) /* get requires driver be up */
-#define IOVF_GET_DOWN (1<<11) /* get requires driver be down */
-#define IOVF_GET_CLK (1<<12) /* get requires core clock */
-#define IOVF_GET_BAND (1<<13) /* get requires fixed band */
-#define IOVF_OPEN_ALLOW (1<<14) /* set allowed iovar for opensrc */
-
-/* watchdog down and dump callback function proto's */
-typedef int (*watchdog_fn_t) (void *handle);
-typedef int (*down_fn_t) (void *handle);
-typedef int (*dump_fn_t) (void *handle, struct brcmu_strbuf *b);
-
-/* IOVar handler
- *
- * handle - a pointer value registered with the function
- * vi - iovar_info that was looked up
- * actionid - action ID, calculated by IOV_GVAL() and IOV_SVAL() based on varid.
- * name - the actual iovar name
- * params/plen - parameters and length for a get, input only.
- * arg/len - buffer and length for value to be set or retrieved, input or output.
- * vsize - value size, valid for integer type only.
- * wlcif - interface context (brcms_c_if pointer)
- *
- * All pointers may point into the same buffer.
- */
-typedef int (*iovar_fn_t) (void *handle, const struct brcmu_iovar *vi,
- u32 actionid, const char *name, void *params,
- uint plen, void *arg, int alen, int vsize,
- struct brcms_c_if *wlcif);
-
#define MAC80211_PROMISC_BCNS (1 << 0)
#define MAC80211_SCAN (1 << 1)
/*
- * Public portion of "common" os-independent state structure.
+ * Public portion of common driver state structure.
* The wlc handle points at this.
*/
struct brcms_pub {
- void *wlc;
-
+ struct brcms_c_info *wlc;
struct ieee80211_hw *ieee_hw;
- struct scb *global_scb;
struct scb_ampdu *global_ampdu;
uint mac80211_state;
uint unit; /* device instance number */
uint corerev; /* core revision */
struct si_pub *sih; /* SI handle (cookie for siutils calls) */
- char *vars; /* "environment" name=value */
bool up; /* interface up and running */
bool hw_off; /* HW is off */
- /* tunables: ntxd, nrxd, maxscb, etc. */
- struct brcms_tunables *tunables;
- bool hw_up; /* one time hw up/down(from boot or hibernation) */
- bool _piomode; /* true if pio mode *//* BMAC_NOTE: NEED In both */
+ bool hw_up; /* one time hw up/down */
+ bool _piomode; /* true if pio mode */
uint _nbands; /* # bands supported */
uint now; /* # elapsed seconds */
bool promisc; /* promiscuous destination address */
bool delayed_down; /* down delayed */
- bool _ap; /* AP mode enabled */
- bool _apsta; /* simultaneous AP/STA mode enabled */
- bool _assoc_recreate; /* association recreation on up transitions */
- int _wme; /* WME QoS mode */
- u8 _mbss; /* MBSS mode on */
- bool allmulti; /* enable all multicasts */
bool associated; /* true:part of [I]BSS, false: not */
/* (union of stas_associated, aps_associated) */
- bool phytest_on; /* whether a PHY test is running */
- bool bf_preempt_4306; /* True to enable 'darwin' mode */
bool _ampdu; /* ampdu enabled or not */
- bool _cac; /* 802.11e CAC enabled */
u8 _n_enab; /* bitmap of 11N + HT support */
- bool _n_reqd; /* N support required for clients */
-
- s8 _coex; /* 20/40 MHz BSS Management AUTO, ENAB, DISABLE */
- bool _priofc; /* Priority-based flowcontrol */
u8 cur_etheraddr[ETH_ALEN]; /* our local ethernet address */
- u8 *multicast; /* ptr to list of multicast addresses */
- uint nmulticast; /* # enabled multicast addresses */
-
- u32 wlfeatureflag; /* Flags to control sw features from registry */
- int psq_pkts_total; /* total num of ps pkts */
-
- u16 txmaxpkts; /* max number of large pkts allowed to be pending */
-
- /* s/w decryption counters */
- u32 swdecrypt; /* s/w decrypt attempts */
-
int bcmerror; /* last bcm error */
- mbool radio_disabled; /* bit vector for radio disabled reasons */
- bool radio_active; /* radio on/off state */
- u16 roam_time_thresh; /* Max. # secs. of not hearing beacons
- * before roaming.
- */
- bool align_wd_tbtt; /* Align watchdog with tbtt indication
- * handling. This flag is cleared by default
- * and is set by per port code explicitly and
- * you need to make sure the OSL_SYSUPTIME()
- * is implemented properly in osl of that port
- * when it enables this Power Save feature.
- */
+ u32 radio_disabled; /* bit vector for radio disabled reasons */
u16 boardrev; /* version # of particular board */
u8 sromrev; /* version # of the srom */
char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */
u32 boardflags; /* Board specific flags from srom */
u32 boardflags2; /* More board flags if sromrev >= 4 */
- bool tempsense_disable; /* disable periodic tempsense check */
bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */
- bool _ampdumac; /* mac assist ampdu enabled or not */
struct wl_cnt *_cnt; /* low-level counters in driver */
};
-/* wl_monitor rx status per packet */
-struct wl_rxsts {
- uint pkterror; /* error flags per pkt */
- uint phytype; /* 802.11 A/B/G ... */
- uint channel; /* channel */
- uint datarate; /* rate in 500kbps */
- uint antenna; /* antenna pkts received on */
- uint pktlength; /* pkt length minus bcm phy hdr */
- u32 mactime; /* time stamp from mac, count per 1us */
- uint sq; /* signal quality */
- s32 signal; /* in dbm */
- s32 noise; /* in dbm */
- uint preamble; /* Unknown, short, long */
- uint encoding; /* Unknown, CCK, PBCC, OFDM */
- uint nfrmtype; /* special 802.11n frames(AMPDU, AMSDU) */
- struct brcms_if *wlif; /* wl interface */
-};
-
-/* status per error RX pkt */
-#define WL_RXS_CRC_ERROR 0x00000001 /* CRC Error in packet */
-#define WL_RXS_RUNT_ERROR 0x00000002 /* Runt packet */
-#define WL_RXS_ALIGN_ERROR 0x00000004 /* Misaligned packet */
-#define WL_RXS_OVERSIZE_ERROR 0x00000008 /* packet bigger than RX_LENGTH (usually 1518) */
-#define WL_RXS_WEP_ICV_ERROR 0x00000010 /* Integrity Check Value error */
-#define WL_RXS_WEP_ENCRYPTED 0x00000020 /* Encrypted with WEP */
-#define WL_RXS_PLCP_SHORT 0x00000040 /* Short PLCP error */
-#define WL_RXS_DECRYPT_ERR 0x00000080 /* Decryption error */
-#define WL_RXS_OTHER_ERR 0x80000000 /* Other errors */
-
-/* phy type */
-#define WL_RXS_PHY_A 0x00000000 /* A phy type */
-#define WL_RXS_PHY_B 0x00000001 /* B phy type */
-#define WL_RXS_PHY_G 0x00000002 /* G phy type */
-#define WL_RXS_PHY_N 0x00000004 /* N phy type */
-
-/* encoding */
-#define WL_RXS_ENCODING_CCK 0x00000000 /* CCK encoding */
-#define WL_RXS_ENCODING_OFDM 0x00000001 /* OFDM encoding */
-
-/* preamble */
-#define WL_RXS_UNUSED_STUB 0x0 /* stub to match with wlc_ethereal.h */
-#define WL_RXS_PREAMBLE_SHORT 0x00000001 /* Short preamble */
-#define WL_RXS_PREAMBLE_LONG 0x00000002 /* Long preamble */
-#define WL_RXS_PREAMBLE_MIMO_MM 0x00000003 /* MIMO mixed mode preamble */
-#define WL_RXS_PREAMBLE_MIMO_GF 0x00000004 /* MIMO green field preamble */
-
-#define WL_RXS_NFRM_AMPDU_FIRST 0x00000001 /* first MPDU in A-MPDU */
-#define WL_RXS_NFRM_AMPDU_SUB 0x00000002 /* subsequent MPDU(s) in A-MPDU */
-#define WL_RXS_NFRM_AMSDU_FIRST 0x00000004 /* first MSDU in A-MSDU */
-#define WL_RXS_NFRM_AMSDU_SUB 0x00000008 /* subsequent MSDU(s) in A-MSDU */
-
enum wlc_par_id {
IOV_MPC = 1,
IOV_RTSTHRESH,
@@ -376,49 +449,15 @@ enum wlc_par_id {
* *********************************************
*/
-/* AP Support (versus STA) */
-#define AP_ENAB(pub) (0)
-
-/* Macro to check if APSTA mode enabled */
-#define APSTA_ENAB(pub) (0)
-
-/* Some useful combinations */
-#define STA_ONLY(pub) (!AP_ENAB(pub))
-#define AP_ONLY(pub) (AP_ENAB(pub) && !APSTA_ENAB(pub))
-
#define ENAB_1x1 0x01
#define ENAB_2x2 0x02
#define ENAB_3x3 0x04
#define ENAB_4x4 0x08
#define SUPPORT_11N (ENAB_1x1|ENAB_2x2)
#define SUPPORT_HT (ENAB_1x1|ENAB_2x2|ENAB_3x3)
-/* WL11N Support */
-#if ((defined(NCONF) && (NCONF != 0)) || (defined(LCNCONF) && (LCNCONF != 0)) || \
- (defined(HTCONF) && (HTCONF != 0)) || (defined(SSLPNCONF) && (SSLPNCONF != 0)))
-#define N_ENAB(pub) ((pub)->_n_enab & SUPPORT_11N)
-#define N_REQD(pub) ((pub)->_n_reqd)
-#else
-#define N_ENAB(pub) 0
-#define N_REQD(pub) 0
-#endif
-
-#if (defined(HTCONF) && (HTCONF != 0))
-#define HT_ENAB(pub) (((pub)->_n_enab & SUPPORT_HT) == SUPPORT_HT)
-#else
-#define HT_ENAB(pub) 0
-#endif
+/* WL11N Support */
#define AMPDU_AGG_HOST 1
-#define AMPDU_ENAB(pub) ((pub)->_ampdu)
-
-#define EDCF_ENAB(pub) (WME_ENAB(pub))
-#define QOS_ENAB(pub) (WME_ENAB(pub) || N_ENAB(pub))
-
-#define MONITOR_ENAB(wlc) ((wlc)->monitor)
-
-#define PROMISC_ENAB(wlc) ((wlc)->promisc)
-
-#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */
/* pri is priority encoded in the packet. This maps the Packet priority to
* enqueue precedence as defined in wlc_prec_map
@@ -426,18 +465,19 @@ enum wlc_par_id {
extern const u8 wlc_prio2prec_map[];
#define BRCMS_PRIO_TO_PREC(pri) wlc_prio2prec_map[(pri) & 7]
-/* This maps priority to one precedence higher - Used by PS-Poll response packets to
- * simulate enqueue-at-head operation, but still maintain the order on the queue
- */
-#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\
- BRCMS_PREC_COUNT - 1)
-
-extern const u8 wme_fifo2ac[];
-#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]]
+#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */
/* Mask to describe all precedence levels */
#define BRCMS_PREC_BMP_ALL MAXBITVAL(BRCMS_PREC_COUNT)
+/*
+ * This maps priority to one precedence higher - Used by PS-Poll response
+ * packets to simulate enqueue-at-head operation, but still maintain the
+ * order on the queue
+ */
+#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\
+ BRCMS_PREC_COUNT - 1)
+
/* Define a bitmap of precedences comprised by each AC */
#define BRCMS_PREC_BMP_AC_BE (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \
@@ -456,14 +496,6 @@ extern const u8 wme_fifo2ac[];
NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) | \
NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC)))
-/* WME Support */
-#define WME_ENAB(pub) ((pub)->_wme != OFF)
-#define WME_AUTO(wlc) ((wlc)->pub->_wme == AUTO)
-
-/* invalid core flags, use the saved coreflags */
-#define BRCMS_USE_COREFLAGS 0xffffffff
-
-
/* network protection config */
#define BRCMS_PROT_G_SPEC 1 /* SPEC g protection */
#define BRCMS_PROT_G_OVR 2 /* SPEC g prot override */
@@ -480,28 +512,34 @@ extern const u8 wme_fifo2ac[];
/*
* 54g modes (basic bits may still be overridden)
*
- * GMODE_LEGACY_B Rateset: 1b, 2b, 5.5, 11
- * Preamble: Long
- * Shortslot: Off
- * GMODE_AUTO Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
- * Extended Rateset: 6, 9, 12, 48
- * Preamble: Long
- * Shortslot: Auto
- * GMODE_ONLY Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54
- * Extended Rateset: 6b, 9, 12b, 48
- * Preamble: Short required
- * Shortslot: Auto
- * GMODE_B_DEFERRED Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
- * Extended Rateset: 6, 9, 12, 48
- * Preamble: Long
- * Shortslot: On
- * GMODE_PERFORMANCE Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54
- * Preamble: Short required
- * Shortslot: On and required
- * GMODE_LRS Rateset: 1b, 2b, 5.5b, 11b
- * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54
- * Preamble: Long
- * Shortslot: Auto
+ * GMODE_LEGACY_B
+ * Rateset: 1b, 2b, 5.5, 11
+ * Preamble: Long
+ * Shortslot: Off
+ * GMODE_AUTO
+ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
+ * Extended Rateset: 6, 9, 12, 48
+ * Preamble: Long
+ * Shortslot: Auto
+ * GMODE_ONLY
+ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54
+ * Extended Rateset: 6b, 9, 12b, 48
+ * Preamble: Short required
+ * Shortslot: Auto
+ * GMODE_B_DEFERRED
+ * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54
+ * Extended Rateset: 6, 9, 12, 48
+ * Preamble: Long
+ * Shortslot: On
+ * GMODE_PERFORMANCE
+ * Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54
+ * Preamble: Short required
+ * Shortslot: On and required
+ * GMODE_LRS
+ * Rateset: 1b, 2b, 5.5b, 11b
+ * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54
+ * Preamble: Long
+ * Shortslot: Auto
*/
#define GMODE_LEGACY_B 0
#define GMODE_AUTO 1
@@ -511,58 +549,13 @@ extern const u8 wme_fifo2ac[];
#define GMODE_LRS 5
#define GMODE_MAX 6
-/* values for PLCPHdr_override */
-#define BRCMS_PLCP_AUTO -1
-#define BRCMS_PLCP_SHORT 0
-#define BRCMS_PLCP_LONG 1
-
-/* values for g_protection_override and n_protection_override */
-#define BRCMS_PROTECTION_AUTO -1
-#define BRCMS_PROTECTION_OFF 0
-#define BRCMS_PROTECTION_ON 1
-#define BRCMS_PROTECTION_MMHDR_ONLY 2
-#define BRCMS_PROTECTION_CTS_ONLY 3
-
-/* values for g_protection_control and n_protection_control */
-#define BRCMS_PROTECTION_CTL_OFF 0
-#define BRCMS_PROTECTION_CTL_LOCAL 1
-#define BRCMS_PROTECTION_CTL_OVERLAP 2
-
-/* values for n_protection */
-#define BRCMS_N_PROTECTION_OFF 0
-#define BRCMS_N_PROTECTION_OPTIONAL 1
-#define BRCMS_N_PROTECTION_20IN40 2
-#define BRCMS_N_PROTECTION_MIXEDMODE 3
-
-/* values for band specific 40MHz capabilities */
-#define BRCMS_N_BW_20ALL 0
-#define BRCMS_N_BW_40ALL 1
-#define BRCMS_N_BW_20IN2G_40IN5G 2
-
-/* bitflags for SGI support (sgi_rx iovar) */
-#define BRCMS_N_SGI_20 0x01
-#define BRCMS_N_SGI_40 0x02
-
-/* defines used by the nrate iovar */
-#define NRATE_MCS_INUSE 0x00000080 /* MSC in use,indicates b0-6 holds an mcs */
-#define NRATE_RATE_MASK 0x0000007f /* rate/mcs value */
-#define NRATE_STF_MASK 0x0000ff00 /* stf mode mask: siso, cdd, stbc, sdm */
-#define NRATE_STF_SHIFT 8 /* stf mode shift */
-#define NRATE_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */
-#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicate to override mcs only */
-#define NRATE_SGI_MASK 0x00800000 /* sgi mode */
-#define NRATE_SGI_SHIFT 23 /* sgi mode */
-#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */
-#define NRATE_LDPC_SHIFT 22 /* ldpc shift */
-
-#define NRATE_STF_SISO 0 /* stf mode SISO */
-#define NRATE_STF_CDD 1 /* stf mode CDD */
-#define NRATE_STF_STBC 2 /* stf mode STBC */
-#define NRATE_STF_SDM 3 /* stf mode SDM */
-
-#define ANT_SELCFG_MAX 4 /* max number of antenna configurations */
-
-#define HIGHEST_SINGLE_STREAM_MCS 7 /* MCS values greater than this enable multiple streams */
+/* MCS values greater than this enable multiple streams */
+#define HIGHEST_SINGLE_STREAM_MCS 7
+
+#define MAXBANDS 2 /* Maximum #of bands */
+
+/* max number of antenna configurations */
+#define ANT_SELCFG_MAX 4
struct brcms_antselcfg {
u8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */
@@ -570,15 +563,14 @@ struct brcms_antselcfg {
};
/* common functions for every port */
-extern void *brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device,
- uint unit, bool piomode, void *regsva, uint bustype,
- void *btparam, uint *perr);
+extern struct brcms_c_info *
+brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
+ bool piomode, void __iomem *regsva, struct pci_dev *btparam,
+ uint *perr);
extern uint brcms_c_detach(struct brcms_c_info *wlc);
extern int brcms_c_up(struct brcms_c_info *wlc);
extern uint brcms_c_down(struct brcms_c_info *wlc);
-extern int brcms_c_set(struct brcms_c_info *wlc, int cmd, int arg);
-extern int brcms_c_get(struct brcms_c_info *wlc, int cmd, int *arg);
extern bool brcms_c_chipmatch(u16 vendor, u16 device);
extern void brcms_c_init(struct brcms_c_info *wlc);
extern void brcms_c_reset(struct brcms_c_info *wlc);
@@ -589,55 +581,31 @@ extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask);
extern bool brcms_c_intrsupd(struct brcms_c_info *wlc);
extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc);
extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded);
-extern bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc,
+extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc,
struct sk_buff *sdu,
struct ieee80211_hw *hw);
-extern int brcms_c_ioctl(struct brcms_c_info *wlc, int cmd, void *arg, int len,
- struct brcms_c_if *wlcif);
extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid);
-
-/* helper functions */
-extern void brcms_c_statsupd(struct brcms_c_info *wlc);
extern void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx,
int val);
extern int brcms_c_get_header_len(void);
-extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc,
- bool promisc);
extern void brcms_c_set_addrmatch(struct brcms_c_info *wlc,
int match_reg_offset,
const u8 *addr);
extern void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
const struct ieee80211_tx_queue_params *arg,
bool suspend);
-extern struct brcms_pub *brcms_c_pub(void *wlc);
-
-/* common functions for every port */
-extern void brcms_c_mhf(struct brcms_c_info *wlc, u8 idx, u16 mask, u16 val,
- int bands);
-extern void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
- wlc_rateset_t *rateset);
-extern void brcms_default_rateset(struct brcms_c_info *wlc, wlc_rateset_t *rs);
-
+extern struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc);
extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
struct ieee80211_sta *sta, u16 tid);
extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
u8 ba_wsize, uint max_rx_ampdu_bytes);
-extern int brcms_c_set_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int val);
-extern int brcms_c_get_par(struct brcms_c_info *wlc, enum wlc_par_id par_id,
- int *ret_int_ptr);
-extern char *getvar(char *vars, const char *name);
-extern int getintvar(char *vars, const char *name);
-
-/* wlc_phy.c helper functions */
-extern void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc);
-extern void brcms_c_mctrl(struct brcms_c_info *wlc, u32 mask, u32 val);
-
+extern char *getvar(struct si_pub *sih, enum brcms_srom_id id);
+extern int getintvar(struct si_pub *sih, enum brcms_srom_id id);
extern int brcms_c_module_register(struct brcms_pub *pub,
- const char *name, void *hdl,
- watchdog_fn_t watchdog_fn, down_fn_t down_fn);
+ const char *name, struct brcms_info *hdl,
+ int (*down_fn)(void *handle));
extern int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
- void *hdl);
+ struct brcms_info *hdl);
extern void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc);
extern void brcms_c_enable_mac(struct brcms_c_info *wlc);
extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state);
@@ -646,20 +614,21 @@ extern void brcms_c_scan_stop(struct brcms_c_info *wlc);
extern int brcms_c_get_curband(struct brcms_c_info *wlc);
extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc,
bool drop);
-
-/* helper functions */
+extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel);
+extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl);
+extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *currs);
+extern int brcms_c_set_rateset(struct brcms_c_info *wlc,
+ struct brcm_rateset *rs);
+extern int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period);
+extern u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx);
+extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc,
+ s8 sslot_override);
+extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
+ u8 interval);
+extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
+extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
+extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
-extern bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc);
-
-#define MAXBANDS 2 /* Maximum #of bands */
-/* bandstate array indices */
-#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */
-#define BAND_5G_INDEX 1 /* wlc->bandstate[x] index */
-
-#define BAND_2G_NAME "2.4G"
-#define BAND_5G_NAME "5G"
-
-/* BMAC RPC: 7 u32 params: pkttotlen, fifo, commit, fid, txpktpend, pktflag, rpc_id */
-#define BRCMS_RPCTX_PARAMS 32
#endif /* _BRCM_PUB_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/rate.c b/drivers/staging/brcm80211/brcmsmac/rate.c
index f0e4b99c2566..0a0c0ad4f96f 100644
--- a/drivers/staging/brcm80211/brcmsmac/rate.c
+++ b/drivers/staging/brcm80211/brcmsmac/rate.c
@@ -21,7 +21,10 @@
#include "pub.h"
#include "rate.h"
-/* Rate info per rate: It tells whether a rate is ofdm or not and its phy_rate value */
+/*
+ * Rate info per rate: It tells whether a rate is ofdm or not and its phy_rate
+ * value
+ */
const u8 rate_info[BRCM_MAXRATE + 1] = {
/* 0 1 2 3 4 5 6 7 8 9 */
/* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -139,20 +142,25 @@ const struct brcms_mcs_info mcs_table[MCS_TABLE_SIZE] = {
{0, 6000, 0, CEIL(6000 * 10, 9), 0x00, BRCM_RATE_6M},
};
-/* phycfg for legacy OFDM frames: code rate, modulation scheme, spatial streams
- * Number of spatial streams: always 1
- * other fields: refer to table 78 of section 17.3.2.2 of the original .11a standard
+/*
+ * phycfg for legacy OFDM frames: code rate, modulation scheme, spatial streams
+ * Number of spatial streams: always 1 other fields: refer to table 78 of
+ * section 17.3.2.2 of the original .11a standard
*/
struct legacy_phycfg {
u32 rate_ofdm; /* ofdm mac rate */
- u8 tx_phy_ctl3; /* phy ctl byte 3, code rate, modulation type, # of streams */
+ /* phy ctl byte 3, code rate, modulation type, # of streams */
+ u8 tx_phy_ctl3;
};
-#define LEGACY_PHYCFG_TABLE_SIZE 12 /* Number of legacy_rate_cfg entries in the table */
+/* Number of legacy_rate_cfg entries in the table */
+#define LEGACY_PHYCFG_TABLE_SIZE 12
-/* In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate */
-/* Eventually MIMOPHY would also be converted to this format */
-/* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */
+/*
+ * In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate
+ * Eventually MIMOPHY would also be converted to this format
+ * 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps
+ */
static const struct
legacy_phycfg legacy_phycfg_table[LEGACY_PHYCFG_TABLE_SIZE] = {
{BRCM_RATE_1M, 0x00}, /* CCK 1Mbps, data rate 0 */
@@ -179,86 +187,89 @@ legacy_phycfg legacy_phycfg_table[LEGACY_PHYCFG_TABLE_SIZE] = {
/* Hardware rates (also encodes default basic rates) */
-const wlc_rateset_t cck_ofdm_mimo_rates = {
+const struct brcms_c_rateset cck_ofdm_mimo_rates = {
12,
- { /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, 54 Mbps */
- 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
- 0x6c},
+ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, */
+ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
+ /* 54 Mbps */
+ 0x6c},
0x00,
- {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
+ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
};
-const wlc_rateset_t ofdm_mimo_rates = {
+const struct brcms_c_rateset ofdm_mimo_rates = {
8,
- { /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
- 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
+ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
0x00,
- {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
+ { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
};
/* Default ratesets that include MCS32 for 40BW channels */
-const wlc_rateset_t cck_ofdm_40bw_mimo_rates = {
+static const struct brcms_c_rateset cck_ofdm_40bw_mimo_rates = {
12,
- { /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, 54 Mbps */
- 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
- 0x6c},
+ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48 */
+ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
+ /* 54 Mbps */
+ 0x6c},
0x00,
- {0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
+ { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
};
-const wlc_rateset_t ofdm_40bw_mimo_rates = {
+static const struct brcms_c_rateset ofdm_40bw_mimo_rates = {
8,
- { /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
- 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
+ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
0x00,
- {0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00}
+ { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00}
};
-const wlc_rateset_t cck_ofdm_rates = {
+const struct brcms_c_rateset cck_ofdm_rates = {
12,
- { /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, 54 Mbps */
- 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
- 0x6c},
+ /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48,*/
+ { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60,
+ /*54 Mbps */
+ 0x6c},
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}
};
-const wlc_rateset_t gphy_legacy_rates = {
+const struct brcms_c_rateset gphy_legacy_rates = {
4,
- { /* 1b, 2b, 5.5b, 11b Mbps */
- 0x82, 0x84, 0x8b, 0x96},
+ /* 1b, 2b, 5.5b, 11b Mbps */
+ { 0x82, 0x84, 0x8b, 0x96},
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}
};
-const wlc_rateset_t ofdm_rates = {
+const struct brcms_c_rateset ofdm_rates = {
8,
- { /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
- 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
+ /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */
+ { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c},
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}
};
-const wlc_rateset_t cck_rates = {
+const struct brcms_c_rateset cck_rates = {
4,
- { /* 1b, 2b, 5.5, 11 Mbps */
- 0x82, 0x84, 0x0b, 0x16},
+ /* 1b, 2b, 5.5, 11 Mbps */
+ { 0x82, 0x84, 0x0b, 0x16},
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}
};
/* check if rateset is valid.
* if check_brate is true, rateset without a basic rate is considered NOT valid.
*/
-static bool brcms_c_rateset_valid(wlc_rateset_t *rs, bool check_brate)
+static bool brcms_c_rateset_valid(struct brcms_c_rateset *rs, bool check_brate)
{
uint idx;
@@ -276,19 +287,20 @@ static bool brcms_c_rateset_valid(wlc_rateset_t *rs, bool check_brate)
return false;
}
-void brcms_c_rateset_mcs_upd(wlc_rateset_t *rs, u8 txstreams)
+void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams)
{
int i;
for (i = txstreams; i < MAX_STREAMS_SUPPORTED; i++)
rs->mcs[i] = 0;
}
-/* filter based on hardware rateset, and sort filtered rateset with basic bit(s) preserved,
- * and check if resulting rateset is valid.
+/*
+ * filter based on hardware rateset, and sort filtered rateset with basic
+ * bit(s) preserved, and check if resulting rateset is valid.
*/
bool
-brcms_c_rate_hwrs_filter_sort_validate(wlc_rateset_t *rs,
- const wlc_rateset_t *hw_rs,
+brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs,
+ const struct brcms_c_rateset *hw_rs,
bool check_brate, u8 txstreams)
{
u8 rateset[BRCM_MAXRATE + 1];
@@ -328,10 +340,10 @@ brcms_c_rate_hwrs_filter_sort_validate(wlc_rateset_t *rs,
}
/* calculate the rate of a rx'd frame and return it as a ratespec */
-ratespec_t brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
+u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
{
int phy_type;
- ratespec_t rspec = PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT;
+ u32 rspec = PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT;
phy_type =
((rxh->RxChan & RXS_CHAN_PHYTYPE_MASK) >> RXS_CHAN_PHYTYPE_SHIFT);
@@ -341,12 +353,12 @@ ratespec_t brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
switch (rxh->PhyRxStatus_0 & PRXS0_FT_MASK) {
case PRXS0_CCK:
rspec =
- CCK_PHY2MAC_RATE(
+ cck_phy2mac_rate(
((struct cck_phy_hdr *) plcp)->signal);
break;
case PRXS0_OFDM:
rspec =
- OFDM_PHY2MAC_RATE(
+ ofdm_phy2mac_rate(
((struct ofdm_phy_hdr *) plcp)->rlpt[0]);
break;
case PRXS0_PREN:
@@ -363,23 +375,24 @@ ratespec_t brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp)
/* not supported, error condition */
break;
}
- if (PLCP3_ISSGI(plcp[3]))
+ if (plcp3_issgi(plcp[3]))
rspec |= RSPEC_SHORT_GI;
} else
if ((phy_type == PHY_TYPE_A) || (rxh->PhyRxStatus_0 & PRXS0_OFDM))
- rspec = OFDM_PHY2MAC_RATE(
+ rspec = ofdm_phy2mac_rate(
((struct ofdm_phy_hdr *) plcp)->rlpt[0]);
else
- rspec = CCK_PHY2MAC_RATE(
+ rspec = cck_phy2mac_rate(
((struct cck_phy_hdr *) plcp)->signal);
return rspec;
}
/* copy rateset src to dst as-is (no masking or sorting) */
-void brcms_c_rateset_copy(const wlc_rateset_t *src, wlc_rateset_t *dst)
+void brcms_c_rateset_copy(const struct brcms_c_rateset *src,
+ struct brcms_c_rateset *dst)
{
- memcpy(dst, src, sizeof(wlc_rateset_t));
+ memcpy(dst, src, sizeof(struct brcms_c_rateset));
}
/*
@@ -392,8 +405,8 @@ void brcms_c_rateset_copy(const wlc_rateset_t *src, wlc_rateset_t *dst)
* 'xmask' is the copy mask (typically 0x7f or 0xff).
*/
void
-brcms_c_rateset_filter(wlc_rateset_t *src, wlc_rateset_t *dst, bool basic_only,
- u8 rates, uint xmask, bool mcsallow)
+brcms_c_rateset_filter(struct brcms_c_rateset *src, struct brcms_c_rateset *dst,
+ bool basic_only, u8 rates, uint xmask, bool mcsallow)
{
uint i;
uint r;
@@ -404,9 +417,11 @@ brcms_c_rateset_filter(wlc_rateset_t *src, wlc_rateset_t *dst, bool basic_only,
r = src->rates[i];
if (basic_only && !(r & BRCMS_RATE_FLAG))
continue;
- if (rates == BRCMS_RATES_CCK && IS_OFDM((r & BRCMS_RATE_MASK)))
+ if (rates == BRCMS_RATES_CCK &&
+ is_ofdm_rate((r & BRCMS_RATE_MASK)))
continue;
- if (rates == BRCMS_RATES_OFDM && IS_CCK((r & BRCMS_RATE_MASK)))
+ if (rates == BRCMS_RATES_OFDM &&
+ is_cck_rate((r & BRCMS_RATE_MASK)))
continue;
dst->rates[count++] = r & xmask;
}
@@ -423,26 +438,27 @@ brcms_c_rateset_filter(wlc_rateset_t *src, wlc_rateset_t *dst, bool basic_only,
* and fill rs_tgt with result
*/
void
-brcms_c_rateset_default(wlc_rateset_t *rs_tgt, const wlc_rateset_t *rs_hw,
- uint phy_type, int bandtype, bool cck_only, uint rate_mask,
- bool mcsallow, u8 bw, u8 txstreams)
+brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt,
+ const struct brcms_c_rateset *rs_hw,
+ uint phy_type, int bandtype, bool cck_only,
+ uint rate_mask, bool mcsallow, u8 bw, u8 txstreams)
{
- const wlc_rateset_t *rs_dflt;
- wlc_rateset_t rs_sel;
+ const struct brcms_c_rateset *rs_dflt;
+ struct brcms_c_rateset rs_sel;
if ((PHYTYPE_IS(phy_type, PHY_TYPE_HT)) ||
(PHYTYPE_IS(phy_type, PHY_TYPE_N)) ||
(PHYTYPE_IS(phy_type, PHY_TYPE_LCN)) ||
(PHYTYPE_IS(phy_type, PHY_TYPE_SSN))) {
- if (BAND_5G(bandtype)) {
+ if (bandtype == BRCM_BAND_5G)
rs_dflt = (bw == BRCMS_20_MHZ ?
&ofdm_mimo_rates : &ofdm_40bw_mimo_rates);
- } else {
+ else
rs_dflt = (bw == BRCMS_20_MHZ ?
&cck_ofdm_mimo_rates :
&cck_ofdm_40bw_mimo_rates);
- }
} else if (PHYTYPE_IS(phy_type, PHY_TYPE_LP)) {
- rs_dflt = (BAND_5G(bandtype)) ? &ofdm_rates : &cck_ofdm_rates;
+ rs_dflt = (bandtype == BRCM_BAND_5G) ?
+ &ofdm_rates : &cck_ofdm_rates;
} else if (PHYTYPE_IS(phy_type, PHY_TYPE_A)) {
rs_dflt = &ofdm_rates;
} else if (PHYTYPE_IS(phy_type, PHY_TYPE_G)) {
@@ -475,21 +491,21 @@ s16 brcms_c_rate_legacy_phyctl(uint rate)
return -1;
}
-void brcms_c_rateset_mcs_clear(wlc_rateset_t *rateset)
+void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset)
{
uint i;
for (i = 0; i < MCSSET_LEN; i++)
rateset->mcs[i] = 0;
}
-void brcms_c_rateset_mcs_build(wlc_rateset_t *rateset, u8 txstreams)
+void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, u8 txstreams)
{
memcpy(&rateset->mcs[0], &cck_ofdm_mimo_rates.mcs[0], MCSSET_LEN);
brcms_c_rateset_mcs_upd(rateset, txstreams);
}
/* Based on bandwidth passed, allow/disallow MCS 32 in the rateset */
-void brcms_c_rateset_bw_mcs_filter(wlc_rateset_t *rateset, u8 bw)
+void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, u8 bw)
{
if (bw == BRCMS_40_MHZ)
setbit(rateset->mcs, 32);
diff --git a/drivers/staging/brcm80211/brcmsmac/rate.h b/drivers/staging/brcm80211/brcmsmac/rate.h
index dbfd3e5816d4..e7b9dc2f2731 100644
--- a/drivers/staging/brcm80211/brcmsmac/rate.h
+++ b/drivers/staging/brcm80211/brcmsmac/rate.h
@@ -18,156 +18,233 @@
#define _BRCM_RATE_H_
#include "types.h"
+#include "d11.h"
extern const u8 rate_info[];
-extern const struct brcms_rateset cck_ofdm_mimo_rates;
-extern const struct brcms_rateset ofdm_mimo_rates;
-extern const struct brcms_rateset cck_ofdm_rates;
-extern const struct brcms_rateset ofdm_rates;
-extern const struct brcms_rateset cck_rates;
-extern const struct brcms_rateset gphy_legacy_rates;
-extern const struct brcms_rateset wlc_lrs_rates;
-extern const struct brcms_rateset rate_limit_1_2;
+extern const struct brcms_c_rateset cck_ofdm_mimo_rates;
+extern const struct brcms_c_rateset ofdm_mimo_rates;
+extern const struct brcms_c_rateset cck_ofdm_rates;
+extern const struct brcms_c_rateset ofdm_rates;
+extern const struct brcms_c_rateset cck_rates;
+extern const struct brcms_c_rateset gphy_legacy_rates;
+extern const struct brcms_c_rateset rate_limit_1_2;
struct brcms_mcs_info {
- u32 phy_rate_20; /* phy rate in kbps [20Mhz] */
- u32 phy_rate_40; /* phy rate in kbps [40Mhz] */
- u32 phy_rate_20_sgi; /* phy rate in kbps [20Mhz] with SGI */
- u32 phy_rate_40_sgi; /* phy rate in kbps [40Mhz] with SGI */
- u8 tx_phy_ctl3; /* phy ctl byte 3, code rate, modulation type, # of streams */
- u8 leg_ofdm; /* matching legacy ofdm rate in 500bkps */
+ /* phy rate in kbps [20Mhz] */
+ u32 phy_rate_20;
+ /* phy rate in kbps [40Mhz] */
+ u32 phy_rate_40;
+ /* phy rate in kbps [20Mhz] with SGI */
+ u32 phy_rate_20_sgi;
+ /* phy rate in kbps [40Mhz] with SGI */
+ u32 phy_rate_40_sgi;
+ /* phy ctl byte 3, code rate, modulation type, # of streams */
+ u8 tx_phy_ctl3;
+ /* matching legacy ofdm rate in 500bkps */
+ u8 leg_ofdm;
};
#define BRCMS_MAXMCS 32 /* max valid mcs index */
#define MCS_TABLE_SIZE 33 /* Number of mcs entries in the table */
extern const struct brcms_mcs_info mcs_table[];
-#define MCS_INVALID 0xFF
-#define MCS_CR_MASK 0x07 /* Code Rate bit mask */
-#define MCS_MOD_MASK 0x38 /* Modulation bit shift */
-#define MCS_MOD_SHIFT 3 /* MOdulation bit shift */
#define MCS_TXS_MASK 0xc0 /* num tx streams - 1 bit mask */
#define MCS_TXS_SHIFT 6 /* num tx streams - 1 bit shift */
-#define MCS_CR(_mcs) (mcs_table[_mcs].tx_phy_ctl3 & MCS_CR_MASK)
-#define MCS_MOD(_mcs) ((mcs_table[_mcs].tx_phy_ctl3 & MCS_MOD_MASK) >> MCS_MOD_SHIFT)
-#define MCS_TXS(_mcs) ((mcs_table[_mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT)
-#define MCS_RATE(_mcs, _is40, _sgi) (_sgi ? \
- (_is40 ? mcs_table[_mcs].phy_rate_40_sgi : mcs_table[_mcs].phy_rate_20_sgi) : \
- (_is40 ? mcs_table[_mcs].phy_rate_40 : mcs_table[_mcs].phy_rate_20))
-#define VALID_MCS(_mcs) ((_mcs < MCS_TABLE_SIZE))
+
+/* returns num tx streams - 1 */
+static inline u8 mcs_2_txstreams(u8 mcs)
+{
+ return (mcs_table[mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT;
+}
+
+static inline uint mcs_2_rate(u8 mcs, bool is40, bool sgi)
+{
+ if (sgi) {
+ if (is40)
+ return mcs_table[mcs].phy_rate_40_sgi;
+ return mcs_table[mcs].phy_rate_20_sgi;
+ }
+ if (is40)
+ return mcs_table[mcs].phy_rate_40;
+
+ return mcs_table[mcs].phy_rate_20;
+}
/* Macro to use the rate_info table */
#define BRCMS_RATE_MASK_FULL 0xff /* Rate value mask with basic rate flag */
-/* convert 500kbps to bps */
-#define BRCMS_RATE_500K_TO_BPS(rate) ((rate) * 500000)
-
-/* rate spec : holds rate and mode specific information required to generate a tx frame. */
-/* Legacy CCK and OFDM information is held in the same manner as was done in the past */
-/* (in the lower byte) the upper 3 bytes primarily hold MIMO specific information */
+/*
+ * rate spec : holds rate and mode specific information required to generate a
+ * tx frame. Legacy CCK and OFDM information is held in the same manner as was
+ * done in the past (in the lower byte) the upper 3 bytes primarily hold MIMO
+ * specific information
+ */
/* rate spec bit fields */
-#define RSPEC_RATE_MASK 0x0000007F /* Either 500Kbps units or MIMO MCS idx */
-#define RSPEC_MIMORATE 0x08000000 /* mimo MCS is stored in RSPEC_RATE_MASK */
-#define RSPEC_BW_MASK 0x00000700 /* mimo bw mask */
-#define RSPEC_BW_SHIFT 8 /* mimo bw shift */
-#define RSPEC_STF_MASK 0x00003800 /* mimo Space/Time/Frequency mode mask */
-#define RSPEC_STF_SHIFT 11 /* mimo Space/Time/Frequency mode shift */
-#define RSPEC_CT_MASK 0x0000C000 /* mimo coding type mask */
-#define RSPEC_CT_SHIFT 14 /* mimo coding type shift */
-#define RSPEC_STC_MASK 0x00300000 /* mimo num STC streams per PLCP defn. */
-#define RSPEC_STC_SHIFT 20 /* mimo num STC streams per PLCP defn. */
-#define RSPEC_LDPC_CODING 0x00400000 /* mimo bit indicates adv coding in use */
-#define RSPEC_SHORT_GI 0x00800000 /* mimo bit indicates short GI in use */
-#define RSPEC_OVERRIDE 0x80000000 /* bit indicates override both rate & mode */
-#define RSPEC_OVERRIDE_MCS_ONLY 0x40000000 /* bit indicates override rate only */
-
-#define BRCMS_HTPHY 127 /* HT PHY Membership */
-
-#define RSPEC_ACTIVE(rspec) (rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE))
-#define RSPEC2RATE(rspec) ((rspec & RSPEC_MIMORATE) ? \
- MCS_RATE((rspec & RSPEC_RATE_MASK), RSPEC_IS40MHZ(rspec), RSPEC_ISSGI(rspec)) : \
- (rspec & RSPEC_RATE_MASK))
-/* return rate in unit of 500Kbps -- for internal use in wlc_rate_sel.c */
-#define RSPEC2RATE500K(rspec) ((rspec & RSPEC_MIMORATE) ? \
- MCS_RATE((rspec & RSPEC_RATE_MASK), state->is40bw, RSPEC_ISSGI(rspec))/500 : \
- (rspec & RSPEC_RATE_MASK))
-#define CRSPEC2RATE500K(rspec) ((rspec & RSPEC_MIMORATE) ? \
- MCS_RATE((rspec & RSPEC_RATE_MASK), RSPEC_IS40MHZ(rspec), RSPEC_ISSGI(rspec))/500 :\
- (rspec & RSPEC_RATE_MASK))
-
-#define RSPEC2KBPS(rspec) (IS_MCS(rspec) ? RSPEC2RATE(rspec) : RSPEC2RATE(rspec)*500)
-#define RSPEC_PHYTXBYTE2(rspec) ((rspec & 0xff00) >> 8)
-#define RSPEC_GET_BW(rspec) ((rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT)
-#define RSPEC_IS40MHZ(rspec) ((((rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT) == \
- PHY_TXC1_BW_40MHZ) || (((rspec & RSPEC_BW_MASK) >> \
- RSPEC_BW_SHIFT) == PHY_TXC1_BW_40MHZ_DUP))
-#define RSPEC_ISSGI(rspec) ((rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI)
-#define RSPEC_MIMOPLCP3(rspec) ((rspec & 0xf00000) >> 16)
-#define PLCP3_ISSGI(plcp) (plcp & (RSPEC_SHORT_GI >> 16))
-#define RSPEC_STC(rspec) ((rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT)
-#define RSPEC_STF(rspec) ((rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT)
-#define PLCP3_ISSTBC(plcp) ((plcp & (RSPEC_STC_MASK) >> 16) == 0x10)
-#define PLCP3_STC_MASK 0x30
-#define PLCP3_STC_SHIFT 4
-
-/* Rate info table; takes a legacy rate or ratespec_t */
-#define IS_MCS(r) (r & RSPEC_MIMORATE)
-#define IS_OFDM(r) (!IS_MCS(r) && (rate_info[(r) & RSPEC_RATE_MASK] & \
- BRCMS_RATE_FLAG))
-#define IS_CCK(r) (!IS_MCS(r) && ( \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_1M || \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_2M || \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_5M5 || \
- ((r) & BRCMS_RATE_MASK) == BRCM_RATE_11M))
-#define IS_SINGLE_STREAM(mcs) (((mcs) <= HIGHEST_SINGLE_STREAM_MCS) || ((mcs) == 32))
-#define CCK_RSPEC(cck) ((cck) & RSPEC_RATE_MASK)
-#define OFDM_RSPEC(ofdm) (((ofdm) & RSPEC_RATE_MASK) |\
- (PHY_TXC1_MODE_CDD << RSPEC_STF_SHIFT))
-#define LEGACY_RSPEC(rate) (IS_CCK(rate) ? CCK_RSPEC(rate) : OFDM_RSPEC(rate))
-
-#define MCS_RSPEC(mcs) (((mcs) & RSPEC_RATE_MASK) | RSPEC_MIMORATE | \
- (IS_SINGLE_STREAM(mcs) ? (PHY_TXC1_MODE_CDD << RSPEC_STF_SHIFT) : \
- (PHY_TXC1_MODE_SDM << RSPEC_STF_SHIFT)))
-
-/* Convert encoded rate value in plcp header to numerical rates in 500 KHz increments */
+
+/* Either 500Kbps units or MIMO MCS idx */
+#define RSPEC_RATE_MASK 0x0000007F
+/* mimo MCS is stored in RSPEC_RATE_MASK */
+#define RSPEC_MIMORATE 0x08000000
+/* mimo bw mask */
+#define RSPEC_BW_MASK 0x00000700
+/* mimo bw shift */
+#define RSPEC_BW_SHIFT 8
+/* mimo Space/Time/Frequency mode mask */
+#define RSPEC_STF_MASK 0x00003800
+/* mimo Space/Time/Frequency mode shift */
+#define RSPEC_STF_SHIFT 11
+/* mimo coding type mask */
+#define RSPEC_CT_MASK 0x0000C000
+/* mimo coding type shift */
+#define RSPEC_CT_SHIFT 14
+/* mimo num STC streams per PLCP defn. */
+#define RSPEC_STC_MASK 0x00300000
+/* mimo num STC streams per PLCP defn. */
+#define RSPEC_STC_SHIFT 20
+/* mimo bit indicates adv coding in use */
+#define RSPEC_LDPC_CODING 0x00400000
+/* mimo bit indicates short GI in use */
+#define RSPEC_SHORT_GI 0x00800000
+/* bit indicates override both rate & mode */
+#define RSPEC_OVERRIDE 0x80000000
+/* bit indicates override rate only */
+#define RSPEC_OVERRIDE_MCS_ONLY 0x40000000
+
+static inline bool rspec_active(u32 rspec)
+{
+ return rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE);
+}
+
+static inline u8 rspec_phytxbyte2(u32 rspec)
+{
+ return (rspec & 0xff00) >> 8;
+}
+
+static inline u32 rspec_get_bw(u32 rspec)
+{
+ return (rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT;
+}
+
+static inline bool rspec_issgi(u32 rspec)
+{
+ return (rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI;
+}
+
+static inline bool rspec_is40mhz(u32 rspec)
+{
+ u32 bw = rspec_get_bw(rspec);
+
+ return bw == PHY_TXC1_BW_40MHZ || bw == PHY_TXC1_BW_40MHZ_DUP;
+}
+
+static inline uint rspec2rate(u32 rspec)
+{
+ if (rspec & RSPEC_MIMORATE)
+ return mcs_2_rate(rspec & RSPEC_RATE_MASK, rspec_is40mhz(rspec),
+ rspec_issgi(rspec));
+ return rspec & RSPEC_RATE_MASK;
+}
+
+static inline u8 rspec_mimoplcp3(u32 rspec)
+{
+ return (rspec & 0xf00000) >> 16;
+}
+
+static inline bool plcp3_issgi(u8 plcp)
+{
+ return (plcp & (RSPEC_SHORT_GI >> 16)) != 0;
+}
+
+static inline uint rspec_stc(u32 rspec)
+{
+ return (rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT;
+}
+
+static inline uint rspec_stf(u32 rspec)
+{
+ return (rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT;
+}
+
+static inline bool is_mcs_rate(u32 ratespec)
+{
+ return (ratespec & RSPEC_MIMORATE) != 0;
+}
+
+static inline bool is_ofdm_rate(u32 ratespec)
+{
+ return !is_mcs_rate(ratespec) &&
+ (rate_info[ratespec & RSPEC_RATE_MASK] & BRCMS_RATE_FLAG);
+}
+
+static inline bool is_cck_rate(u32 ratespec)
+{
+ u32 rate = (ratespec & BRCMS_RATE_MASK);
+
+ return !is_mcs_rate(ratespec) && (
+ rate == BRCM_RATE_1M || rate == BRCM_RATE_2M ||
+ rate == BRCM_RATE_5M5 || rate == BRCM_RATE_11M);
+}
+
+static inline bool is_single_stream(u8 mcs)
+{
+ return mcs <= HIGHEST_SINGLE_STREAM_MCS || mcs == 32;
+}
+
+static inline u8 cck_rspec(u8 cck)
+{
+ return cck & RSPEC_RATE_MASK;
+}
+
+/* Convert encoded rate value in plcp header to numerical rates in 500 KHz
+ * increments */
extern const u8 ofdm_rate_lookup[];
-#define OFDM_PHY2MAC_RATE(rlpt) (ofdm_rate_lookup[rlpt & 0x7])
-#define CCK_PHY2MAC_RATE(signal) (signal/5)
+
+static inline u8 ofdm_phy2mac_rate(u8 rlpt)
+{
+ return ofdm_rate_lookup[rlpt & 0x7];
+}
+
+static inline u8 cck_phy2mac_rate(u8 signal)
+{
+ return signal/5;
+}
/* Rates specified in brcms_c_rateset_filter() */
#define BRCMS_RATES_CCK_OFDM 0
#define BRCMS_RATES_CCK 1
#define BRCMS_RATES_OFDM 2
-/* sanitize, and sort a rateset with the basic bit(s) preserved, validate rateset */
+/* sanitize, and sort a rateset with the basic bit(s) preserved, validate
+ * rateset */
extern bool
-brcms_c_rate_hwrs_filter_sort_validate(struct brcms_rateset *rs,
- const struct brcms_rateset *hw_rs,
+brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs,
+ const struct brcms_c_rateset *hw_rs,
bool check_brate, u8 txstreams);
/* copy rateset src to dst as-is (no masking or sorting) */
-extern void brcms_c_rateset_copy(const struct brcms_rateset *src,
- struct brcms_rateset *dst);
+extern void brcms_c_rateset_copy(const struct brcms_c_rateset *src,
+ struct brcms_c_rateset *dst);
/* would be nice to have these documented ... */
-extern ratespec_t brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp);
+extern u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp);
-extern void brcms_c_rateset_filter(struct brcms_rateset *src,
- struct brcms_rateset *dst, bool basic_only, u8 rates, uint xmask,
+extern void brcms_c_rateset_filter(struct brcms_c_rateset *src,
+ struct brcms_c_rateset *dst, bool basic_only, u8 rates, uint xmask,
bool mcsallow);
extern void
-brcms_c_rateset_default(struct brcms_rateset *rs_tgt,
- const struct brcms_rateset *rs_hw, uint phy_type,
+brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt,
+ const struct brcms_c_rateset *rs_hw, uint phy_type,
int bandtype, bool cck_only, uint rate_mask,
bool mcsallow, u8 bw, u8 txstreams);
extern s16 brcms_c_rate_legacy_phyctl(uint rate);
-extern void brcms_c_rateset_mcs_upd(struct brcms_rateset *rs, u8 txstreams);
-extern void brcms_c_rateset_mcs_clear(struct brcms_rateset *rateset);
-extern void brcms_c_rateset_mcs_build(struct brcms_rateset *rateset,
+extern void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams);
+extern void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset);
+extern void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset,
u8 txstreams);
-extern void brcms_c_rateset_bw_mcs_filter(struct brcms_rateset *rateset, u8 bw);
+extern void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset,
+ u8 bw);
#endif /* _BRCM_RATE_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/scb.h b/drivers/staging/brcm80211/brcmsmac/scb.h
index d6c8328554d0..51c79c7239b7 100644
--- a/drivers/staging/brcm80211/brcmsmac/scb.h
+++ b/drivers/staging/brcm80211/brcmsmac/scb.h
@@ -23,17 +23,27 @@
#include "types.h"
#define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */
+
+#define AMPDU_MAX_SCB_TID NUMPRIO
+
+/* scb flags */
+#define SCB_WMECAP 0x0040
+#define SCB_HTCAP 0x10000 /* HT (MIMO) capable device */
+#define SCB_IS40 0x80000 /* 40MHz capable */
+#define SCB_STBCCAP 0x40000000 /* STBC Capable */
+
+#define SCB_MAGIC 0xbeefcafe
+
/* structure to store per-tid state for the ampdu initiator */
struct scb_ampdu_tid_ini {
- u8 tx_in_transit; /* number of pending mpdus in transit in driver */
- u8 tid; /* initiator tid for easy lookup */
- u8 txretry[AMPDU_TX_BA_MAX_WSIZE]; /* tx retry count; indexed by seq modulo */
- struct scb *scb; /* backptr for easy lookup */
- u8 ba_wsize; /* negotiated ba window size (in pdu) */
+ u8 tx_in_transit; /* number of pending mpdus in transit in driver */
+ u8 tid; /* initiator tid for easy lookup */
+ /* tx retry count; indexed by seq modulo */
+ u8 txretry[AMPDU_TX_BA_MAX_WSIZE];
+ struct scb *scb; /* backptr for easy lookup */
+ u8 ba_wsize; /* negotiated ba window size (in pdu) */
};
-#define AMPDU_MAX_SCB_TID NUMPRIO
-
struct scb_ampdu {
struct scb *scb; /* back pointer for easy reference */
u8 mpdu_density; /* mpdu density */
@@ -41,45 +51,32 @@ struct scb_ampdu {
u8 release; /* # of mpdus released at a time */
u16 min_len; /* min mpdu len to support the density */
u32 max_rx_ampdu_bytes; /* max ampdu rcv length; 8k, 16k, 32k, 64k */
- struct pktq txq; /* sdu transmit queue pending aggregation */
- /* This could easily be a ini[] pointer and we keep this info in wl itself instead
- * of having mac80211 hold it for us. Also could be made dynamic per tid instead of
- * static.
+ /*
+ * This could easily be a ini[] pointer and we keep this info in wl
+ * itself instead of having mac80211 hold it for us. Also could be made
+ * dynamic per tid instead of static.
*/
/* initiator info - per tid (NUMPRIO): */
struct scb_ampdu_tid_ini ini[AMPDU_MAX_SCB_TID];
};
-#define SCB_MAGIC 0xbeefcafe
-
/* station control block - one per remote MAC address */
struct scb {
u32 magic;
- u32 flags; /* various bit flags as defined below */
- u32 flags2; /* various bit flags2 as defined below */
- u8 state; /* current state bitfield of auth/assoc process */
+ u32 flags; /* various bit flags as defined below */
+ u32 flags2; /* various bit flags2 as defined below */
+ u8 state; /* current state bitfield of auth/assoc process */
u8 ea[ETH_ALEN]; /* station address */
- void *fragbuf[NUMPRIO]; /* defragmentation buffer per prio */
- uint fragresid[NUMPRIO]; /* #bytes unused in frag buffer per prio */
+ uint fragresid[NUMPRIO];/* #bytes unused in frag buffer per prio */
u16 seqctl[NUMPRIO]; /* seqctl of last received frame (for dups) */
- u16 seqctl_nonqos; /* seqctl of last received frame (for dups) for
- * non-QoS data and management
- */
- u16 seqnum[NUMPRIO]; /* WME: driver maintained sw seqnum per priority */
+ /* seqctl of last received frame (for dups) for non-QoS data and
+ * management */
+ u16 seqctl_nonqos;
+ u16 seqnum[NUMPRIO];/* WME: driver maintained sw seqnum per priority */
struct scb_ampdu scb_ampdu; /* AMPDU state including per tid info */
};
-/* scb flags */
-#define SCB_WMECAP 0x0040 /* may ONLY be set if WME_ENAB(wlc) */
-#define SCB_HTCAP 0x10000 /* HT (MIMO) capable device */
-#define SCB_IS40 0x80000 /* 40MHz capable */
-#define SCB_STBCCAP 0x40000000 /* STBC Capable */
-#define SCB_WME(a) ((a)->flags & SCB_WMECAP)/* implies WME_ENAB */
-#define SCB_SEQNUM(scb, prio) ((scb)->seqnum[(prio)])
-#define SCB_PS(a) NULL
-#define SCB_STBC_CAP(a) ((a)->flags & SCB_STBCCAP)
-#define SCB_AMPDU(a) true
#endif /* _BRCM_SCB_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/srom.c b/drivers/staging/brcm80211/brcmsmac/srom.c
index f39442ed4ce7..99f791048e84 100644
--- a/drivers/staging/brcm80211/brcmsmac/srom.c
+++ b/drivers/staging/brcm80211/brcmsmac/srom.c
@@ -18,24 +18,23 @@
#include <linux/string.h>
#include <linux/io.h>
#include <linux/etherdevice.h>
+#include <linux/crc8.h>
#include <stdarg.h>
#include <chipcommon.h>
#include <brcmu_utils.h>
+#include "pub.h"
#include "nicpci.h"
#include "aiutils.h"
#include "otp.h"
#include "srom.h"
-#define SROM_OFFSET(sih) ((sih->ccrev > 31) ? \
- (((sih->cccaps & CC_CAP_SROM) == 0) ? NULL : \
- ((u8 *)curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP)) : \
- ((u8 *)curmap + PCI_BAR0_SPROM_OFFSET))
-
-#if defined(BCMDBG)
-#define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
-#define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
-#endif
+/*
+ * SROM CRC8 polynomial value:
+ *
+ * x^8 + x^7 +x^6 + x^4 + x^2 + 1
+ */
+#define SROM_CRC8_POLY 0xAB
/* Maximum srom: 6 Kilobits == 768 bytes */
#define SROM_MAX 768
@@ -260,7 +259,8 @@
/* Temp sense related entries */
#define SROM8_MPWR_RAWTS 90
#define SROM8_TS_SLP_OPT_CORRX 91
-/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */
+/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable,
+ * IQSWP: IQ CAL swap disable */
#define SROM8_FOC_HWIQ_IQSWP 92
/* Temperature delta for PHY calibration */
@@ -349,20 +349,53 @@
#define SROM9_PO_LOFDM40DUP 203
/* SROM flags (see sromvar_t) */
-#define SRFL_MORE 1 /* value continues as described by the next entry */
+
+/* value continues as described by the next entry */
+#define SRFL_MORE 1
#define SRFL_NOFFS 2 /* value bits can't be all one's */
#define SRFL_PRHEX 4 /* value is in hexdecimal format */
#define SRFL_PRSIGN 8 /* value is in signed decimal format */
#define SRFL_CCODE 0x10 /* value is in country code format */
#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
-#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */
+/* do not generate a nvram param, entry is for mfgc */
+#define SRFL_NOVAR 0x80
/* Max. nvram variable table size */
#define MAXSZ_NVRAM_VARS 4096
+/*
+ * indicates type of value.
+ */
+enum brcms_srom_var_type {
+ BRCMS_SROM_STRING,
+ BRCMS_SROM_SNUMBER,
+ BRCMS_SROM_UNUMBER
+};
+
+/*
+ * storage type for srom variable.
+ *
+ * var_list: for linked list operations.
+ * varid: identifier of the variable.
+ * var_type: type of variable.
+ * buf: variable value when var_type == BRCMS_SROM_STRING.
+ * uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER.
+ * sval: signed variable value when var_type == BRCMS_SROM_SNUMBER.
+ */
+struct brcms_srom_list_head {
+ struct list_head var_list;
+ enum brcms_srom_id varid;
+ enum brcms_srom_var_type var_type;
+ union {
+ char buf[0];
+ u32 uval;
+ s32 sval;
+ };
+};
+
struct brcms_sromvar {
- const char *name;
+ enum brcms_srom_id varid;
u32 revmask;
u32 flags;
u16 off;
@@ -375,615 +408,476 @@ struct brcms_varbuf {
unsigned int size; /* current (residual) size in bytes */
};
-/* Assumptions:
- * - Ethernet address spans across 3 consective words
+/*
+ * Assumptions:
+ * - Ethernet address spans across 3 consecutive words
*
* Table rules:
- * - Add multiple entries next to each other if a value spans across multiple words
- * (even multiple fields in the same word) with each entry except the last having
- * it's SRFL_MORE bit set.
- * - Ethernet address entry does not follow above rule and must not have SRFL_MORE
- * bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
- * - The last entry's name field must be NULL to indicate the end of the table. Other
- * entries must have non-NULL name.
+ * - Add multiple entries next to each other if a value spans across multiple
+ * words (even multiple fields in the same word) with each entry except the
+ * last having it's SRFL_MORE bit set.
+ * - Ethernet address entry does not follow above rule and must not have
+ * SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
+ * - The last entry's name field must be NULL to indicate the end of the table.
+ * Other entries must have non-NULL name.
*/
static const struct brcms_sromvar pci_sromvars[] = {
- {"devid", 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID, 0xffff},
- {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK},
- {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
- {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
- {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
- {"boardflags", 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
- {"", 0, 0, SROM_BFL2, 0xffff},
- {"boardflags", 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
- {"", 0, 0, SROM3_BFL2, 0xffff},
- {"boardflags", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, 0xffff},
- {"", 0, 0, SROM4_BFL1, 0xffff},
- {"boardflags", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, 0xffff},
- {"", 0, 0, SROM5_BFL1, 0xffff},
- {"boardflags", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, 0xffff},
- {"", 0, 0, SROM8_BFL1, 0xffff},
- {"boardflags2", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, 0xffff},
- {"", 0, 0, SROM4_BFL3, 0xffff},
- {"boardflags2", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, 0xffff},
- {"", 0, 0, SROM5_BFL3, 0xffff},
- {"boardflags2", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, 0xffff},
- {"", 0, 0, SROM8_BFL3, 0xffff},
- {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
- {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
- {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff},
- {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff},
- {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff},
- {"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff},
- {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
- {"regrev", 0x00000008, 0, SROM_OPO, 0xff00},
- {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff},
- {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff},
- {"regrev", 0xffffff00, 0, SROM8_REGREV, 0x00ff},
- {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
- {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
- {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
- {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
- {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
- {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
- {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
- {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
- {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
- {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
- {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
- {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
- {"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
- {"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
- {"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
- {"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
- {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
- {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
- {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
- {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff},
- {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
- {"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
- {"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
- {"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
- {"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
- {"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
- {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff},
- {"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
- {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
- {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff},
- {"aa2g", 0xffffff00, 0, SROM8_AA, 0x00ff},
- {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
- {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00},
- {"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00},
- {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff},
- {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00},
- {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff},
- {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00},
- {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff},
- {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00},
- {"ag0", 0xffffff00, 0, SROM8_AG10, 0x00ff},
- {"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00},
- {"ag2", 0xffffff00, 0, SROM8_AG32, 0x00ff},
- {"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00},
- {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
- {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
- {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
- {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
- {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
- {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
- {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
- {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
- {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
- {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00},
- {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
- {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
- {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
- {"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
- {"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
- {"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
- {"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
- {"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
- {"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
- {"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
- {"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
- {"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
- {"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
- {"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
- {"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
- {"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
- {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
- {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
- {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
- {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
- {"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
- {"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
- {"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
- {"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
- {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
- {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
- {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
- {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
- {"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
- {"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
- {"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
- {"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
- {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff},
- {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00},
- {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
- {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00},
- {"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
- {"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00},
- {"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
- {"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
- {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
- {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
- {"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
- {"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
- {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK},
- {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK},
- {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK},
- {"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK},
- {"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK},
- {"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK},
- {"tssipos2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK},
- {"extpagain2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK},
- {"pdetrange2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK},
- {"triso2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
- {"antswctl2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK},
- {"tssipos5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK},
- {"extpagain5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK},
- {"pdetrange5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK},
- {"triso5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
- {"antswctl5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK},
- {"tempthresh", 0xffffff00, 0, SROM8_THERMAL, 0xff00},
- {"tempoffset", 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
- {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
- {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
- {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
- {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
- {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
- {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
- {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
- {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
- {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
- {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
- {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
- {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
- {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
- {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
- {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
- {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
-
- {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
- {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
- {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
- {"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
- {"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
- {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
- {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
- {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
- {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff},
- {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff},
- {"leddc", 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, 0xffff},
- {"leddc", 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, 0xffff},
- {"leddc", 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, 0xffff},
- {"leddc", 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, 0xffff},
- {"rawtempsense", 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff},
- {"measpower", 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00},
- {"tempsense_slope", 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
+ {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
+ 0xffff},
+ {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV,
+ SROM_BR_MASK},
+ {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
+ {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff},
+ {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
+ 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
+ {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff},
+ {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
+ {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
+ {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00},
+ {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff},
+ {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff},
+ {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
+ {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
+ {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
+ {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
+ {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
+ {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
+ {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
+ {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
+ {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
+ {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
+ {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
+ {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff},
+ {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
+ {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
+ {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
+ {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
+ {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
+ {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
+ {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff},
+ {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
+ {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
+ {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff},
+ {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
+ {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
+ {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00},
+ {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
+ {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff},
+ {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00},
+ {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff},
+ {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00},
+ {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff},
+ {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00},
+ {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
+ {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
+ {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
+ {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
+ {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
+ {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
+ {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
+ {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
+ {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
+ {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
+ {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
+ {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
+ {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
+ {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00},
+ {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
+ {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
+ {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
+ {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
+ {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
+ {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
+ {BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
+ {BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
+ {BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
+ {BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
+ {BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
+ {BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
+ {BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
+ {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
+ {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
+ {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
+ {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
+ {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
+ {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
+ {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
+ {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
+ {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
+ {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
+ {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
+ {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
+ {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
+ {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
+ {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
+ {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
+ {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
+ {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
+ {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
+ {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff},
+ {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00},
+ {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
+ {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00},
+ {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
+ {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
+ {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
+ {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
+ {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
+ {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
+ {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
+ {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
+ {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
+ SROM4_TXCHAIN_MASK},
+ {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
+ SROM4_RXCHAIN_MASK},
+ {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
+ SROM4_SWITCH_MASK},
+ {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
+ SROM4_TXCHAIN_MASK},
+ {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
+ SROM4_RXCHAIN_MASK},
+ {BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
+ SROM4_SWITCH_MASK},
+ {BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_TSSIPOS_MASK},
+ {BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_EXTPA_GAIN_MASK},
+ {BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_PDET_RANGE_MASK},
+ {BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
+ {BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G,
+ SROM8_FEM_ANTSWLUT_MASK},
+ {BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_TSSIPOS_MASK},
+ {BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_EXTPA_GAIN_MASK},
+ {BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_PDET_RANGE_MASK},
+ {BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
+ {BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G,
+ SROM8_FEM_ANTSWLUT_MASK},
+ {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
+ {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
+ {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
+ {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
+ {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
+ {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
+ {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
+ {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
+ {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
+ {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
+ {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
+ {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
+ {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
+ {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
+ {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
+ {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
+ {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
+ {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
+
+ {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
+ {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
+ {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+ {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
+ {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
+ {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
+ {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
+ {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
+ {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0,
+ 0xffff},
+ {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC,
+ 0xffff},
+ {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
+ 0x01ff},
+ {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
+ 0xfe00},
+ {BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX,
+ SROM8_TS_SLP_OPT_CORRX, 0x00ff},
+ {BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
+ 0xfc00},
+ {BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX,
+ SROM8_TS_SLP_OPT_CORRX, 0x0300},
+ {BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX,
+ SROM8_FOC_HWIQ_IQSWP, 0x000f},
+ {BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
+ 0x0010},
+ {BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
+ 0x0020},
+ {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
0x00ff},
- {"tempcorrx", 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00},
- {"tempsense_option", 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
- 0x0300},
- {"freqoffset_corr", 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
- 0x000f},
- {"iqcal_swp_dis", 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010},
- {"hw_iqcal_en", 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020},
- {"phycal_tempdelta", 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff},
-
- {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
- {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
- {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
- {"", 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
- {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
- {"", 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
- {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
- {"", 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
- {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
- {"", 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
- {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
- {"", 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
- {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
- {"", 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
- {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
- {"", 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
- {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
- {"", 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
- {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
- {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
- {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
- {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
- {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
- {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
- {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
- {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
- {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
- {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
- {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
- {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
- {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
- {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
- {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
- {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
- {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
- {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
- {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
- {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
- {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
- {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
- {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
- {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
- {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
- {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
- {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
- {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
- {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
- {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
- {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
- {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
- {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
- {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
- {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
- {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
- {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
- {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
- {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
- {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
- {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
- {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
- {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
- {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
- {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
- {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
- {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
- {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
- {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
- {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
- {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
- {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
- {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
- {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
- {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
- {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
- {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
- {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
- {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
- {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
- {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
- {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
- {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
- {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
- {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff},
- {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff},
- {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff},
- {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
- {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff},
- {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff},
- {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff},
- {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
+
+ {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
+ {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
+ {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
+ {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
+ {BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
+ {BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
+ {BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
+ {BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
+ {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
+ {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
+ {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
+ {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff},
+ {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff},
+ {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff},
+ {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
+ {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
+ {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
+ {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
+ {BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
/* power per rate from sromrev 9 */
- {"cckbw202gpo", 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
- {"cckbw20ul2gpo", 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
- {"legofdmbw202gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_LOFDMBW20,
+ {BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
+ {BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE,
+ SROM9_2GPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE,
+ SROM9_2GPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GLPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GLPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GMPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GMPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GHPO_LOFDMBW20, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
+ {BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GHPO_LOFDMBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20,
0xffff},
- {"", 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
- {"legofdmbw20ul2gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_LOFDMBW20UL,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL,
0xffff},
- {"", 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
- {"legofdmbw205glpo", 0xfffffe00, SRFL_MORE, SROM9_5GLPO_LOFDMBW20,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40,
0xffff},
- {"", 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
- {"legofdmbw20ul5glpo", 0xfffffe00, SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20,
0xffff},
- {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
- {"legofdmbw205gmpo", 0xfffffe00, SRFL_MORE, SROM9_5GMPO_LOFDMBW20,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GLPO_MCSBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40,
0xffff},
- {"", 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
- {"legofdmbw20ul5gmpo", 0xfffffe00, SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20,
0xffff},
- {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
- {"legofdmbw205ghpo", 0xfffffe00, SRFL_MORE, SROM9_5GHPO_LOFDMBW20,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GMPO_MCSBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40,
0xffff},
- {"", 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
- {"legofdmbw20ul5ghpo", 0xfffffe00, SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20,
0xffff},
- {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
- {"mcsbw202gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff},
- {"", 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
- {"mcsbw20ul2gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff},
- {"", 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
- {"mcsbw402gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff},
- {"", 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
- {"mcsbw205glpo", 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff},
- {"", 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
- {"mcsbw20ul5glpo", 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20UL,
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
+ {BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
+ SROM9_5GHPO_MCSBW20UL, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
+ {BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40,
0xffff},
- {"", 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
- {"mcsbw405glpo", 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff},
- {"", 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
- {"mcsbw205gmpo", 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff},
- {"", 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
- {"mcsbw20ul5gmpo", 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20UL,
- 0xffff},
- {"", 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
- {"mcsbw405gmpo", 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff},
- {"", 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
- {"mcsbw205ghpo", 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff},
- {"", 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
- {"mcsbw20ul5ghpo", 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20UL,
- 0xffff},
- {"", 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
- {"mcsbw405ghpo", 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff},
- {"", 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
- {"mcs32po", 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
- {"legofdm40duppo", 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
+ {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
+ {BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
+ {BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
- {NULL, 0, 0, 0, 0}
+ {BRCMS_SROM_NULL, 0, 0, 0, 0}
};
static const struct brcms_sromvar perpath_pci_sromvars[] = {
- {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
- {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
- {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
- {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
- {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
- {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
- {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
- {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
- {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
- {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
- {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
- {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
- {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
- {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
- {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
- {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, 0xffff},
- {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, 0xffff},
- {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, 0xffff},
- {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
- {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, 0xffff},
- {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, 0xffff},
- {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, 0xffff},
- {"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
- {"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
- {"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
- {"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
- {"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
- {"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
- {"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
- {"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
- {"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
- {"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
- {"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
- {"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
- {"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
- {"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, 0xffff},
- {"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, 0xffff},
- {"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
- {"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, 0xffff},
- {"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, 0xffff},
- {NULL, 0, 0, 0, 0}
+ {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
+ {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
+ {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
+ {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
+ {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
+ {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
+ {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
+ {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
+ {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
+ {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3,
+ 0xffff},
+ {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
+ {BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
+ {BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
+ {BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
+ {BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
+ {BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
+ {BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
+ {BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
+ {BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
+ {BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
+ {BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1,
+ 0xffff},
+ {BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2,
+ 0xffff},
+ {BRCMS_SROM_NULL, 0, 0, 0, 0}
};
-static void _initvars_srom_pci(u8 sromrev, u16 *srom, uint off,
- struct brcms_varbuf *b);
-static int initvars_srom_pci(struct si_pub *sih, void *curmap, char **vars,
- uint *count);
-static int sprom_read_pci(struct si_pub *sih, u16 *sprom,
- uint wordoff, u16 *buf, uint nwords, bool check_crc);
-#if defined(BCMNVRAMR)
-static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz);
-#endif
-
-static int initvars_table(char *start, char *end,
- char **vars, uint *count);
-
-/* Initialization of varbuf structure */
-static void varbuf_init(struct brcms_varbuf *b, char *buf, uint size)
-{
- b->size = size;
- b->base = b->buf = buf;
-}
-
-/* append a null terminated var=value string */
-static int varbuf_append(struct brcms_varbuf *b, const char *fmt, ...)
-{
- va_list ap;
- int r;
- size_t len;
- char *s;
-
- if (b->size < 2)
- return 0;
-
- va_start(ap, fmt);
- r = vsnprintf(b->buf, b->size, fmt, ap);
- va_end(ap);
-
- /* C99 snprintf behavior returns r >= size on overflow,
- * others return -1 on overflow.
- * All return -1 on format error.
- * We need to leave room for 2 null terminations, one for the current var
- * string, and one for final null of the var table. So check that the
- * strlen written, r, leaves room for 2 chars.
- */
- if ((r == -1) || (r > (int)(b->size - 2))) {
- b->size = 0;
- return 0;
- }
-
- /* Remove any earlier occurrence of the same variable */
- s = strchr(b->buf, '=');
- if (s != NULL) {
- len = (size_t) (s - b->buf);
- for (s = b->base; s < b->buf;) {
- if ((memcmp(s, b->buf, len) == 0) && s[len] == '=') {
- len = strlen(s) + 1;
- memmove(s, (s + len),
- ((b->buf + r + 1) - (s + len)));
- b->buf -= len;
- b->size += (unsigned int)len;
- break;
- }
-
- while (*s++)
- ;
- }
- }
-
- /* skip over this string's null termination */
- r++;
- b->size -= r;
- b->buf += r;
-
- return r;
-}
-
-/*
- * Initialize local vars from the right source for this platform.
- * Return 0 on success, nonzero on error.
- */
-int srom_var_init(struct si_pub *sih, uint bustype, void *curmap,
- char **vars, uint *count)
-{
- uint len;
-
- len = 0;
-
- if (vars == NULL || count == NULL)
- return 0;
-
- *vars = NULL;
- *count = 0;
-
- if (curmap != NULL && bustype == PCI_BUS)
- return initvars_srom_pci(sih, curmap, vars, count);
-
- return -EINVAL;
-}
-
-static inline void ltoh16_buf(u16 *buf, unsigned int size)
-{
- for (size /= 2; size; size--)
- *(buf + size) = le16_to_cpu(*(buf + size));
-}
-
-static inline void htol16_buf(u16 *buf, unsigned int size)
-{
- for (size /= 2; size; size--)
- *(buf + size) = cpu_to_le16(*(buf + size));
-}
-
-/*
- * Read in and validate sprom.
- * Return 0 on success, nonzero on error.
- */
-static int
-sprom_read_pci(struct si_pub *sih, u16 *sprom, uint wordoff,
- u16 *buf, uint nwords, bool check_crc)
-{
- int err = 0;
- uint i;
-
- /* read the sprom */
- for (i = 0; i < nwords; i++)
- buf[i] = R_REG(&sprom[wordoff + i]);
-
- if (check_crc) {
-
- if (buf[0] == 0xffff) {
- /* The hardware thinks that an srom that starts with 0xffff
- * is blank, regardless of the rest of the content, so declare
- * it bad.
- */
- return -ENODATA;
- }
-
- /* fixup the endianness so crc8 will pass */
- htol16_buf(buf, nwords * 2);
- if (brcmu_crc8((u8 *) buf, nwords * 2, CRC8_INIT_VALUE) !=
- CRC8_GOOD_VALUE) {
- /* DBG only pci always read srom4 first, then srom8/9 */
- err = -EIO;
- }
- /* now correct the endianness of the byte array */
- ltoh16_buf(buf, nwords * 2);
- }
- return err;
-}
-
-#if defined(BCMNVRAMR)
-static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
-{
- u8 *otp;
- uint sz = OTP_SZ_MAX / 2; /* size in words */
- int err = 0;
-
- otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
- if (otp == NULL) {
- return -ENOMEM;
- }
-
- err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
-
- memcpy(buf, otp, bufsz);
-
- kfree(otp);
-
- /* Check CRC */
- if (buf[0] == 0xffff) {
- /* The hardware thinks that an srom that starts with 0xffff
- * is blank, regardless of the rest of the content, so declare
- * it bad.
- */
- return -ENODATA;
- }
-
- /* fixup the endianness so crc8 will pass */
- htol16_buf(buf, bufsz);
- if (brcmu_crc8((u8 *) buf, SROM4_WORDS * 2, CRC8_INIT_VALUE) !=
- CRC8_GOOD_VALUE) {
- err = -EIO;
- }
- /* now correct the endianness of the byte array */
- ltoh16_buf(buf, bufsz);
+/* crc table has the same contents for every device instance, so it can be
+ * shared between devices. */
+static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
- return err;
-}
-#endif /* defined(BCMNVRAMR) */
-/*
-* Create variable table from memory.
-* Return 0 on success, nonzero on error.
-*/
-static int initvars_table(char *start, char *end,
- char **vars, uint *count)
+static u16 __iomem *
+srom_window_address(struct si_pub *sih, u8 __iomem *curmap)
{
- int c = (int)(end - start);
-
- /* do it only when there is more than just the null string */
- if (c > 1) {
- char *vp = kmalloc(c, GFP_ATOMIC);
- if (!vp)
- return -ENOMEM;
- memcpy(vp, start, c);
- *vars = vp;
- *count = c;
- } else {
- *vars = NULL;
- *count = 0;
- }
+ if (sih->ccrev < 32)
+ return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET);
+ if (sih->cccaps & CC_CAP_SROM)
+ return (u16 __iomem *)
+ (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP);
- return 0;
+ return NULL;
}
/* Parse SROM and create name=value pairs. 'srom' points to
@@ -1012,9 +906,28 @@ static uint mask_width(u16 mask)
return 0;
}
+static inline void ltoh16_buf(u16 *buf, unsigned int size)
+{
+ size /= 2;
+ while (size--)
+ *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size));
+}
+
+static inline void htol16_buf(u16 *buf, unsigned int size)
+{
+ size /= 2;
+ while (size--)
+ *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size));
+}
+
+/*
+ * convert binary srom data into linked list of srom variable items.
+ */
static void
-_initvars_srom_pci(u8 sromrev, u16 *srom, uint off, struct brcms_varbuf *b)
+_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
{
+ struct brcms_srom_list_head *entry;
+ enum brcms_srom_id id;
u16 w;
u32 val;
const struct brcms_sromvar *srv;
@@ -1022,46 +935,52 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, struct brcms_varbuf *b)
uint flags;
u32 sr = (1 << sromrev);
- varbuf_append(b, "sromrev=%d", sromrev);
+ /* first store the srom revision */
+ entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
+ entry->varid = BRCMS_SROM_REV;
+ entry->var_type = BRCMS_SROM_UNUMBER;
+ entry->uval = sromrev;
+ list_add(&entry->var_list, var_list);
- for (srv = pci_sromvars; srv->name != NULL; srv++) {
- const char *name;
+ for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) {
+ enum brcms_srom_var_type type;
+ u8 ea[ETH_ALEN];
+ u8 extra_space = 0;
if ((srv->revmask & sr) == 0)
continue;
- if (srv->off < off)
- continue;
-
flags = srv->flags;
- name = srv->name;
+ id = srv->varid;
/* This entry is for mfgc only. Don't generate param for it, */
if (flags & SRFL_NOVAR)
continue;
if (flags & SRFL_ETHADDR) {
- u8 ea[ETH_ALEN];
-
- ea[0] = (srom[srv->off - off] >> 8) & 0xff;
- ea[1] = srom[srv->off - off] & 0xff;
- ea[2] = (srom[srv->off + 1 - off] >> 8) & 0xff;
- ea[3] = srom[srv->off + 1 - off] & 0xff;
- ea[4] = (srom[srv->off + 2 - off] >> 8) & 0xff;
- ea[5] = srom[srv->off + 2 - off] & 0xff;
-
- varbuf_append(b, "%s=%pM", name, ea);
+ /*
+ * stored in string format XX:XX:XX:XX:XX:XX (17 chars)
+ */
+ ea[0] = (srom[srv->off] >> 8) & 0xff;
+ ea[1] = srom[srv->off] & 0xff;
+ ea[2] = (srom[srv->off + 1] >> 8) & 0xff;
+ ea[3] = srom[srv->off + 1] & 0xff;
+ ea[4] = (srom[srv->off + 2] >> 8) & 0xff;
+ ea[5] = srom[srv->off + 2] & 0xff;
+ /* 17 characters + string terminator - union size */
+ extra_space = 18 - sizeof(s32);
+ type = BRCMS_SROM_STRING;
} else {
- w = srom[srv->off - off];
+ w = srom[srv->off];
val = (w & srv->mask) >> mask_shift(srv->mask);
width = mask_width(srv->mask);
while (srv->flags & SRFL_MORE) {
srv++;
- if (srv->off == 0 || srv->off < off)
+ if (srv->off == 0)
continue;
- w = srom[srv->off - off];
+ w = srom[srv->off];
val +=
((w & srv->mask) >> mask_shift(srv->
mask)) <<
@@ -1074,28 +993,42 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, struct brcms_varbuf *b)
continue;
if (flags & SRFL_CCODE) {
- if (val == 0)
- varbuf_append(b, "ccode=");
- else
- varbuf_append(b, "ccode=%c%c",
- (val >> 8), (val & 0xff));
- }
- /* LED Powersave duty cycle has to be scaled:
- *(oncount >> 24) (offcount >> 8)
- */
- else if (flags & SRFL_LEDDC) {
- u32 w32 = (((val >> 8) & 0xff) << 24) | /* oncount */
- (((val & 0xff)) << 8); /* offcount */
- varbuf_append(b, "leddc=%d", w32);
- } else if (flags & SRFL_PRHEX)
- varbuf_append(b, "%s=0x%x", name, val);
- else if ((flags & SRFL_PRSIGN)
- && (val & (1 << (width - 1))))
- varbuf_append(b, "%s=%d", name,
- (int)(val | (~0 << width)));
+ type = BRCMS_SROM_STRING;
+ } else if (flags & SRFL_LEDDC) {
+ /* LED Powersave duty cycle has to be scaled:
+ *(oncount >> 24) (offcount >> 8)
+ */
+ u32 w32 = /* oncount */
+ (((val >> 8) & 0xff) << 24) |
+ /* offcount */
+ (((val & 0xff)) << 8);
+ type = BRCMS_SROM_UNUMBER;
+ val = w32;
+ } else if ((flags & SRFL_PRSIGN)
+ && (val & (1 << (width - 1)))) {
+ type = BRCMS_SROM_SNUMBER;
+ val |= ~0 << width;
+ } else
+ type = BRCMS_SROM_UNUMBER;
+ }
+
+ entry = kzalloc(sizeof(struct brcms_srom_list_head) +
+ extra_space, GFP_KERNEL);
+ entry->varid = id;
+ entry->var_type = type;
+ if (flags & SRFL_ETHADDR) {
+ snprintf(entry->buf, 18, "%pM", ea);
+ } else if (flags & SRFL_CCODE) {
+ if (val == 0)
+ entry->buf[0] = '\0';
else
- varbuf_append(b, "%s=%u", name, val);
+ snprintf(entry->buf, 3, "%c%c",
+ (val >> 8), (val & 0xff));
+ } else {
+ entry->uval = val;
}
+
+ list_add(&entry->var_list, var_list);
}
if (sromrev >= 4) {
@@ -1111,34 +1044,31 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, struct brcms_varbuf *b)
}
for (p = 0; p < MAX_PATH_SROM; p++) {
- for (srv = perpath_pci_sromvars; srv->name != NULL;
- srv++) {
+ for (srv = perpath_pci_sromvars;
+ srv->varid != BRCMS_SROM_NULL; srv++) {
if ((srv->revmask & sr) == 0)
continue;
- if (pb + srv->off < off)
- continue;
-
- /* This entry is for mfgc only. Don't generate param for it, */
if (srv->flags & SRFL_NOVAR)
continue;
- w = srom[pb + srv->off - off];
+ w = srom[pb + srv->off];
val = (w & srv->mask) >> mask_shift(srv->mask);
width = mask_width(srv->mask);
- /* Cheating: no per-path var is more than 1 word */
-
+ /* Cheating: no per-path var is more than
+ * 1 word */
if ((srv->flags & SRFL_NOFFS)
&& ((int)val == (1 << width) - 1))
continue;
- if (srv->flags & SRFL_PRHEX)
- varbuf_append(b, "%s%d=0x%x", srv->name,
- p, val);
- else
- varbuf_append(b, "%s%d=%d", srv->name,
- p, val);
+ entry =
+ kzalloc(sizeof(struct brcms_srom_list_head),
+ GFP_KERNEL);
+ entry->varid = srv->varid+p;
+ entry->var_type = BRCMS_SROM_UNUMBER;
+ entry->uval = val;
+ list_add(&entry->var_list, var_list);
}
pb += psz;
}
@@ -1146,17 +1076,90 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, uint off, struct brcms_varbuf *b)
}
/*
+ * Read in and validate sprom.
+ * Return 0 on success, nonzero on error.
+ */
+static int
+sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff,
+ u16 *buf, uint nwords, bool check_crc)
+{
+ int err = 0;
+ uint i;
+
+ /* read the sprom */
+ for (i = 0; i < nwords; i++)
+ buf[i] = R_REG(&sprom[wordoff + i]);
+
+ if (check_crc) {
+
+ if (buf[0] == 0xffff)
+ /*
+ * The hardware thinks that an srom that starts with
+ * 0xffff is blank, regardless of the rest of the
+ * content, so declare it bad.
+ */
+ return -ENODATA;
+
+ /* fixup the endianness so crc8 will pass */
+ htol16_buf(buf, nwords * 2);
+ if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2,
+ CRC8_INIT_VALUE) !=
+ CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+ /* DBG only pci always read srom4 first, then srom8/9 */
+ err = -EIO;
+
+ /* now correct the endianness of the byte array */
+ ltoh16_buf(buf, nwords * 2);
+ }
+ return err;
+}
+
+static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
+{
+ u8 *otp;
+ uint sz = OTP_SZ_MAX / 2; /* size in words */
+ int err = 0;
+
+ otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
+ if (otp == NULL)
+ return -ENOMEM;
+
+ err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
+
+ memcpy(buf, otp, bufsz);
+
+ kfree(otp);
+
+ /* Check CRC */
+ if (buf[0] == 0xffff)
+ /* The hardware thinks that an srom that starts with 0xffff
+ * is blank, regardless of the rest of the content, so declare
+ * it bad.
+ */
+ return -ENODATA;
+
+ /* fixup the endianness so crc8 will pass */
+ htol16_buf(buf, bufsz);
+ if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2,
+ CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+ err = -EIO;
+
+ /* now correct the endianness of the byte array */
+ ltoh16_buf(buf, bufsz);
+
+ return err;
+}
+
+/*
* Initialize nonvolatile variable table from sprom.
* Return 0 on success, nonzero on error.
*/
-static int initvars_srom_pci(struct si_pub *sih, void *curmap, char **vars,
- uint *count)
+static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
{
- u16 *srom, *sromwindow;
+ u16 *srom;
+ u16 __iomem *sromwindow;
u8 sromrev = 0;
u32 sr;
- struct brcms_varbuf b;
- char *vp, *base = NULL;
int err = 0;
/*
@@ -1166,7 +1169,9 @@ static int initvars_srom_pci(struct si_pub *sih, void *curmap, char **vars,
if (!srom)
return -ENOMEM;
- sromwindow = (u16 *) SROM_OFFSET(sih);
+ sromwindow = srom_window_address(sih, curmap);
+
+ crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
if (ai_is_sprom_available(sih)) {
err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
true);
@@ -1188,50 +1193,106 @@ static int initvars_srom_pci(struct si_pub *sih, void *curmap, char **vars,
if (sromrev == 0x10)
sromrev = 1;
}
- }
-#if defined(BCMNVRAMR)
- /* Use OTP if SPROM not available */
- else {
+ } else {
+ /* Use OTP if SPROM not available */
err = otp_read_pci(sih, srom, SROM_MAX);
if (err == 0)
/* OTP only contain SROM rev8/rev9 for now */
sromrev = srom[SROM4_CRCREV] & 0xff;
}
-#else
- else
- err = -ENODEV;
-#endif
if (!err) {
+ struct si_info *sii = (struct si_info *)sih;
+
/* Bitmask for the sromrev */
sr = 1 << sromrev;
- /* srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, 9 */
+ /*
+ * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8,
+ * 9
+ */
if ((sr & 0x33e) == 0) {
err = -EINVAL;
goto errout;
}
- base = kmalloc(MAXSZ_NVRAM_VARS, GFP_ATOMIC);
- if (!base) {
- err = -ENOMEM;
- goto errout;
- }
-
- varbuf_init(&b, base, MAXSZ_NVRAM_VARS);
+ INIT_LIST_HEAD(&sii->var_list);
/* parse SROM into name=value pairs. */
- _initvars_srom_pci(sromrev, srom, 0, &b);
-
- /* final nullbyte terminator */
- vp = b.buf;
- *vp++ = '\0';
-
- err = initvars_table(base, vp, vars, count);
- kfree(base);
+ _initvars_srom_pci(sromrev, srom, &sii->var_list);
}
errout:
kfree(srom);
return err;
}
+
+void srom_free_vars(struct si_pub *sih)
+{
+ struct si_info *sii;
+ struct brcms_srom_list_head *entry, *next;
+
+ sii = (struct si_info *)sih;
+ list_for_each_entry_safe(entry, next, &sii->var_list, var_list) {
+ list_del(&entry->var_list);
+ kfree(entry);
+ }
+}
+/*
+ * Initialize local vars from the right source for this platform.
+ * Return 0 on success, nonzero on error.
+ */
+int srom_var_init(struct si_pub *sih, void __iomem *curmap)
+{
+ uint len;
+
+ len = 0;
+
+ if (curmap != NULL)
+ return initvars_srom_pci(sih, curmap);
+
+ return -EINVAL;
+}
+
+/*
+ * Search the name=value vars for a specific one and return its value.
+ * Returns NULL if not found.
+ */
+char *getvar(struct si_pub *sih, enum brcms_srom_id id)
+{
+ struct si_info *sii;
+ struct brcms_srom_list_head *entry;
+
+ sii = (struct si_info *)sih;
+
+ list_for_each_entry(entry, &sii->var_list, var_list)
+ if (entry->varid == id)
+ return &entry->buf[0];
+
+ /* nothing found */
+ return NULL;
+}
+
+/*
+ * Search the vars for a specific one and return its value as
+ * an integer. Returns 0 if not found.-
+ */
+int getintvar(struct si_pub *sih, enum brcms_srom_id id)
+{
+ struct si_info *sii;
+ struct brcms_srom_list_head *entry;
+ unsigned long res;
+
+ sii = (struct si_info *)sih;
+
+ list_for_each_entry(entry, &sii->var_list, var_list)
+ if (entry->varid == id) {
+ if (entry->var_type == BRCMS_SROM_SNUMBER ||
+ entry->var_type == BRCMS_SROM_UNUMBER)
+ return (int)entry->sval;
+ else if (!kstrtoul(&entry->buf[0], 0, &res))
+ return (int)res;
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/brcm80211/brcmsmac/srom.h b/drivers/staging/brcm80211/brcmsmac/srom.h
index efc4d1edd86d..708c43ff51cc 100644
--- a/drivers/staging/brcm80211/brcmsmac/srom.h
+++ b/drivers/staging/brcm80211/brcmsmac/srom.h
@@ -20,8 +20,8 @@
#include "types.h"
/* Prototypes */
-extern int srom_var_init(struct si_pub *sih, uint bus, void *curmap,
- char **vars, uint *count);
+extern int srom_var_init(struct si_pub *sih, void __iomem *curmap);
+extern void srom_free_vars(struct si_pub *sih);
extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
uint byteoff, uint nbytes, u16 *buf, bool check_crc);
diff --git a/drivers/staging/brcm80211/brcmsmac/stf.c b/drivers/staging/brcm80211/brcmsmac/stf.c
index a55ff0101782..d8f528eb180c 100644
--- a/drivers/staging/brcm80211/brcmsmac/stf.c
+++ b/drivers/staging/brcm80211/brcmsmac/stf.c
@@ -22,7 +22,6 @@
#include "phy/phy_hal.h"
#include "channel.h"
#include "main.h"
-#include "bmac.h"
#include "stf.h"
#define MIN_SPATIAL_EXPANSION 0
@@ -31,20 +30,12 @@
#define BRCMS_STF_SS_STBC_RX(wlc) (BRCMS_ISNPHY(wlc->band) && \
NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6))
-static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val);
-static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts, u8 val);
-static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val);
-static void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val);
-
-static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
-static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
- ratespec_t rspec);
-
#define NSTS_1 1
#define NSTS_2 2
#define NSTS_3 3
#define NSTS_4 4
-const u8 txcore_default[5] = {
+
+static const u8 txcore_default[5] = {
(0), /* bitmap of the core enabled */
(0x01), /* For Nsts = 1, enable core 1 */
(0x03), /* For Nsts = 2, enable core 1 & 2 */
@@ -60,16 +51,16 @@ static void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val)
return;
}
- wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_RX_STBC;
- wlc->ht_cap.cap_info |= (val << IEEE80211_HT_CAP_RX_STBC_SHIFT);
-
if (wlc->pub->up) {
brcms_c_update_beacon(wlc);
brcms_c_update_probe_resp(wlc, true);
}
}
-/* every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to turn on/off txchain */
+/*
+ * every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to
+ * turn on/off txchain.
+ */
void brcms_c_tempsense_upd(struct brcms_c_info *wlc)
{
struct brcms_phy_pub *pi = wlc->band->pi;
@@ -81,21 +72,19 @@ void brcms_c_tempsense_upd(struct brcms_c_info *wlc)
txchain = active_chains & 0xf;
if (wlc->stf->txchain == wlc->stf->hw_txchain) {
- if (txchain && (txchain < wlc->stf->hw_txchain)) {
+ if (txchain && (txchain < wlc->stf->hw_txchain))
/* turn off 1 tx chain */
brcms_c_stf_txchain_set(wlc, txchain, true);
- }
} else if (wlc->stf->txchain < wlc->stf->hw_txchain) {
- if (txchain == wlc->stf->hw_txchain) {
+ if (txchain == wlc->stf->hw_txchain)
/* turn back on txchain */
brcms_c_stf_txchain_set(wlc, txchain, true);
- }
}
}
void
brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
- chanspec_t chanspec)
+ u16 chanspec)
{
struct tx_power power;
u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id;
@@ -120,16 +109,19 @@ brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
/* criteria to choose stf mode */
- /* the "+3dbm (12 0.25db units)" is to account for the fact that with CDD, tx occurs
- * on both chains
+ /*
+ * the "+3dbm (12 0.25db units)" is to account for the fact that with
+ * CDD, tx occurs on both chains
*/
if (power.target[siso_mcs_id] > (power.target[cdd_mcs_id] + 12))
setbit(ss_algo_channel, PHY_TXC1_MODE_SISO);
else
setbit(ss_algo_channel, PHY_TXC1_MODE_CDD);
- /* STBC is ORed into to algo channel as STBC requires per-packet SCB capability check
- * so cannot be default mode of operation. One of SISO, CDD have to be set
+ /*
+ * STBC is ORed into to algo channel as STBC requires per-packet SCB
+ * capability check so cannot be default mode of operation. One of
+ * SISO, CDD have to be set
*/
if (power.target[siso_mcs_id] <= (power.target[stbc_mcs_id] + 12))
setbit(ss_algo_channel, PHY_TXC1_MODE_STBC);
@@ -137,19 +129,12 @@ brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel,
static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val)
{
- if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON)) {
+ if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON))
return false;
- }
if ((int_val == ON) && (wlc->stf->txstreams == 1))
return false;
- if ((int_val == OFF) || (wlc->stf->txstreams == 1)
- || !BRCMS_STBC_CAP_PHY(wlc))
- wlc->ht_cap.cap_info &= ~IEEE80211_HT_CAP_TX_STBC;
- else
- wlc->ht_cap.cap_info |= IEEE80211_HT_CAP_TX_STBC;
-
wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = (s8) int_val;
wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = (s8) int_val;
@@ -159,9 +144,8 @@ static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val)
bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val)
{
if ((int_val != HT_CAP_RX_STBC_NO)
- && (int_val != HT_CAP_RX_STBC_ONE_STREAM)) {
+ && (int_val != HT_CAP_RX_STBC_ONE_STREAM))
return false;
- }
if (BRCMS_STF_SS_STBC_RX(wlc)) {
if ((int_val != HT_CAP_RX_STBC_NO)
@@ -179,15 +163,13 @@ static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts,
BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n",
wlc->pub->unit, Nsts, core_mask);
- if (BRCMS_BITSCNT(core_mask) > wlc->stf->txstreams) {
+ if (hweight8(core_mask) > wlc->stf->txstreams)
core_mask = 0;
- }
- if ((BRCMS_BITSCNT(core_mask) == wlc->stf->txstreams) &&
+ if ((hweight8(core_mask) == wlc->stf->txstreams) &&
((core_mask & ~wlc->stf->txchain)
- || !(core_mask & wlc->stf->txchain))) {
+ || !(core_mask & wlc->stf->txchain)))
core_mask = wlc->stf->txchain;
- }
wlc->stf->txcore[Nsts] = core_mask;
/* Nsts = 1..4, txcore index = 1..4 */
@@ -223,6 +205,60 @@ static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val)
return 0;
}
+/*
+ * Centralized txant update function. call it whenever wlc->stf->txant and/or
+ * wlc->stf->txchain change.
+ *
+ * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to
+ * achieve various tx/rx antenna selection schemes
+ *
+ * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7
+ * means auto(last rx).
+ * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7
+ * means last rx and do tx-antenna selection for SISO transmissions
+ * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7
+ * means last rx and do tx-antenna selection for SISO transmissions
+ * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7
+ * means both cores active
+*/
+static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
+{
+ s8 txant;
+
+ txant = (s8) wlc->stf->txant;
+ if (BRCMS_PHY_11N_CAP(wlc->band)) {
+ if (txant == ANT_TX_FORCE_0) {
+ wlc->stf->phytxant = PHY_TXC_ANT_0;
+ } else if (txant == ANT_TX_FORCE_1) {
+ wlc->stf->phytxant = PHY_TXC_ANT_1;
+
+ if (BRCMS_ISNPHY(wlc->band) &&
+ NREV_GE(wlc->band->phyrev, 3)
+ && NREV_LT(wlc->band->phyrev, 7))
+ wlc->stf->phytxant = PHY_TXC_ANT_2;
+ } else {
+ if (BRCMS_ISLCNPHY(wlc->band) ||
+ BRCMS_ISSSLPNPHY(wlc->band))
+ wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST;
+ else {
+ /* catch out of sync wlc->stf->txcore */
+ WARN_ON(wlc->stf->txchain <= 0);
+ wlc->stf->phytxant =
+ wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
+ }
+ }
+ } else {
+ if (txant == ANT_TX_FORCE_0)
+ wlc->stf->phytxant = PHY_TXC_OLD_ANT_0;
+ else if (txant == ANT_TX_FORCE_1)
+ wlc->stf->phytxant = PHY_TXC_OLD_ANT_1;
+ else
+ wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST;
+ }
+
+ brcms_b_txant_set(wlc->hw, wlc->stf->phytxant);
+}
+
int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force)
{
u8 txchain = (u8) int_val;
@@ -236,41 +272,14 @@ int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force)
|| !(txchain & wlc->stf->hw_txchain))
return -EINVAL;
- /* if nrate override is configured to be non-SISO STF mode, reject reducing txchain to 1 */
- txstreams = (u8) BRCMS_BITSCNT(txchain);
+ /*
+ * if nrate override is configured to be non-SISO STF mode, reject
+ * reducing txchain to 1
+ */
+ txstreams = (u8) hweight8(txchain);
if (txstreams > MAX_STREAMS_SUPPORTED)
return -EINVAL;
- if (txstreams == 1) {
- for (i = 0; i < NBANDS(wlc); i++)
- if ((RSPEC_STF(wlc->bandstate[i]->rspec_override) !=
- PHY_TXC1_MODE_SISO)
- || (RSPEC_STF(wlc->bandstate[i]->mrspec_override) !=
- PHY_TXC1_MODE_SISO)) {
- if (!force)
- return -EBADE;
-
- /* over-write the override rspec */
- if (RSPEC_STF(wlc->bandstate[i]->rspec_override)
- != PHY_TXC1_MODE_SISO) {
- wlc->bandstate[i]->rspec_override = 0;
- wiphy_err(wlc->wiphy, "%s(): temp "
- "sense override non-SISO "
- "rspec_override\n",
- __func__);
- }
- if (RSPEC_STF
- (wlc->bandstate[i]->mrspec_override) !=
- PHY_TXC1_MODE_SISO) {
- wlc->bandstate[i]->mrspec_override = 0;
- wiphy_err(wlc->wiphy, "%s(): temp "
- "sense override non-SISO "
- "mrspec_override\n",
- __func__);
- }
- }
- }
-
wlc->stf->txchain = txchain;
wlc->stf->txstreams = txstreams;
brcms_c_stf_stbc_tx_set(wlc, wlc->band->band_stf_stbc_tx);
@@ -289,7 +298,10 @@ int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force)
return 0;
}
-/* update wlc->stf->ss_opmode which represents the operational stf_ss mode we're using */
+/*
+ * update wlc->stf->ss_opmode which represents the operational stf_ss mode
+ * we're using
+ */
int brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band)
{
int ret_code = 0;
@@ -298,21 +310,22 @@ int brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band)
prev_stf_ss = wlc->stf->ss_opmode;
- /* NOTE: opmode can only be SISO or CDD as STBC is decided on a per-packet basis */
+ /*
+ * NOTE: opmode can only be SISO or CDD as STBC is decided on a
+ * per-packet basis
+ */
if (BRCMS_STBC_CAP_PHY(wlc) &&
wlc->stf->ss_algosel_auto
&& (wlc->stf->ss_algo_channel != (u16) -1)) {
- upd_stf_ss = (wlc->stf->no_cddstbc || (wlc->stf->txstreams == 1)
- || isset(&wlc->stf->ss_algo_channel,
- PHY_TXC1_MODE_SISO)) ? PHY_TXC1_MODE_SISO
- : PHY_TXC1_MODE_CDD;
+ upd_stf_ss = (wlc->stf->txstreams == 1 ||
+ isset(&wlc->stf->ss_algo_channel,
+ PHY_TXC1_MODE_SISO)) ?
+ PHY_TXC1_MODE_SISO : PHY_TXC1_MODE_CDD;
} else {
if (wlc->band != band)
return ret_code;
- upd_stf_ss = (wlc->stf->no_cddstbc
- || (wlc->stf->txstreams ==
- 1)) ? PHY_TXC1_MODE_SISO : band->
- band_stf_ss_mode;
+ upd_stf_ss = (wlc->stf->txstreams == 1) ?
+ PHY_TXC1_MODE_SISO : band->band_stf_ss_mode;
}
if (prev_stf_ss != upd_stf_ss) {
wlc->stf->ss_opmode = upd_stf_ss;
@@ -340,7 +353,8 @@ int brcms_c_stf_attach(struct brcms_c_info *wlc)
if (BRCMS_STBC_CAP_PHY(wlc)) {
wlc->stf->ss_algosel_auto = true;
- wlc->stf->ss_algo_channel = (u16) -1; /* Init the default value */
+ /* Init the default value */
+ wlc->stf->ss_algo_channel = (u16) -1;
}
return 0;
}
@@ -349,59 +363,6 @@ void brcms_c_stf_detach(struct brcms_c_info *wlc)
{
}
-/*
- * Centralized txant update function. call it whenever wlc->stf->txant and/or wlc->stf->txchain
- * change
- *
- * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to
- * achieve various tx/rx antenna selection schemes
- *
- * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 means auto(last rx)
- * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 means last rx and
- * do tx-antenna selection for SISO transmissions
- * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7 means last rx and
- * do tx-antenna selection for SISO transmissions
- * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 means both cores active
-*/
-static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
-{
- s8 txant;
-
- txant = (s8) wlc->stf->txant;
- if (BRCMS_PHY_11N_CAP(wlc->band)) {
- if (txant == ANT_TX_FORCE_0) {
- wlc->stf->phytxant = PHY_TXC_ANT_0;
- } else if (txant == ANT_TX_FORCE_1) {
- wlc->stf->phytxant = PHY_TXC_ANT_1;
-
- if (BRCMS_ISNPHY(wlc->band) &&
- NREV_GE(wlc->band->phyrev, 3)
- && NREV_LT(wlc->band->phyrev, 7)) {
- wlc->stf->phytxant = PHY_TXC_ANT_2;
- }
- } else {
- if (BRCMS_ISLCNPHY(wlc->band) ||
- BRCMS_ISSSLPNPHY(wlc->band))
- wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST;
- else {
- /* catch out of sync wlc->stf->txcore */
- WARN_ON(wlc->stf->txchain <= 0);
- wlc->stf->phytxant =
- wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
- }
- }
- } else {
- if (txant == ANT_TX_FORCE_0)
- wlc->stf->phytxant = PHY_TXC_OLD_ANT_0;
- else if (txant == ANT_TX_FORCE_1)
- wlc->stf->phytxant = PHY_TXC_OLD_ANT_1;
- else
- wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST;
- }
-
- brcms_b_txant_set(wlc->hw, wlc->stf->phytxant);
-}
-
void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
{
_brcms_c_stf_phy_txant_upd(wlc);
@@ -410,31 +371,29 @@ void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
{
/* get available rx/tx chains */
- wlc->stf->hw_txchain = (u8) getintvar(wlc->pub->vars, "txchain");
- wlc->stf->hw_rxchain = (u8) getintvar(wlc->pub->vars, "rxchain");
+ wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN);
+ wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN);
/* these parameter are intended to be used for all PHY types */
if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) {
- if (BRCMS_ISNPHY(wlc->band)) {
+ if (BRCMS_ISNPHY(wlc->band))
wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY;
- } else {
+ else
wlc->stf->hw_txchain = TXCHAIN_DEF;
- }
}
wlc->stf->txchain = wlc->stf->hw_txchain;
- wlc->stf->txstreams = (u8) BRCMS_BITSCNT(wlc->stf->hw_txchain);
+ wlc->stf->txstreams = (u8) hweight8(wlc->stf->hw_txchain);
if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) {
- if (BRCMS_ISNPHY(wlc->band)) {
+ if (BRCMS_ISNPHY(wlc->band))
wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY;
- } else {
+ else
wlc->stf->hw_rxchain = RXCHAIN_DEF;
- }
}
wlc->stf->rxchain = wlc->stf->hw_rxchain;
- wlc->stf->rxstreams = (u8) BRCMS_BITSCNT(wlc->stf->hw_rxchain);
+ wlc->stf->rxstreams = (u8) hweight8(wlc->stf->hw_rxchain);
/* initialize the txcore table */
memcpy(wlc->stf->txcore, txcore_default, sizeof(wlc->stf->txcore));
@@ -445,24 +404,24 @@ void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
}
static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
- ratespec_t rspec)
+ u32 rspec)
{
u16 phytxant = wlc->stf->phytxant;
- if (RSPEC_STF(rspec) != PHY_TXC1_MODE_SISO) {
+ if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO)
phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
- } else if (wlc->stf->txant == ANT_TX_DEF)
+ else if (wlc->stf->txant == ANT_TX_DEF)
phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT;
phytxant &= PHY_TXC_ANT_MASK;
return phytxant;
}
-u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, ratespec_t rspec)
+u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec)
{
return _brcms_c_stf_phytxchain_sel(wlc, rspec);
}
-u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, ratespec_t rspec)
+u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec)
{
u16 phytxant = wlc->stf->phytxant;
u16 mask = PHY_TXC_ANT_MASK;
diff --git a/drivers/staging/brcm80211/brcmsmac/stf.h b/drivers/staging/brcm80211/brcmsmac/stf.h
index 06c2a399649e..19f6580f69be 100644
--- a/drivers/staging/brcm80211/brcmsmac/stf.h
+++ b/drivers/staging/brcm80211/brcmsmac/stf.h
@@ -25,7 +25,7 @@ extern void brcms_c_stf_detach(struct brcms_c_info *wlc);
extern void brcms_c_tempsense_upd(struct brcms_c_info *wlc);
extern void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc,
u16 *ss_algo_channel,
- chanspec_t chanspec);
+ u16 chanspec);
extern int brcms_c_stf_ss_update(struct brcms_c_info *wlc,
struct brcms_band *band);
extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
@@ -35,8 +35,8 @@ extern bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val);
extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc);
extern void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc);
extern u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc,
- ratespec_t rspec);
+ u32 rspec);
extern u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc,
- ratespec_t rspec);
+ u32 rspec);
#endif /* _BRCM_STF_H_ */
diff --git a/drivers/staging/brcm80211/brcmsmac/types.h b/drivers/staging/brcm80211/brcmsmac/types.h
index 823b5e4672e2..27a814b07462 100644
--- a/drivers/staging/brcm80211/brcmsmac/types.h
+++ b/drivers/staging/brcm80211/brcmsmac/types.h
@@ -20,59 +20,77 @@
#include <linux/types.h>
#include <linux/io.h>
-/* Bus types */
-#define SI_BUS 0 /* SOC Interconnect */
-#define PCI_BUS 1 /* PCI target */
-#define SDIO_BUS 3 /* SDIO target */
-#define JTAG_BUS 4 /* JTAG */
-#define USB_BUS 5 /* USB (does not support R/W REG) */
-#define SPI_BUS 6 /* gSPI target */
-#define RPC_BUS 7 /* RPC target */
-
#define WL_CHAN_FREQ_RANGE_2G 0
#define WL_CHAN_FREQ_RANGE_5GL 1
#define WL_CHAN_FREQ_RANGE_5GM 2
#define WL_CHAN_FREQ_RANGE_5GH 3
-#define MAX_DMA_SEGS 4
-
/* boardflags */
-#define BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */
-#define BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */
-#define BFL_FEM 0x00000800 /* Board supports the Front End Module */
-#define BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
-#define BFL_NOPA 0x00010000 /* Board has no PA */
-#define BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */
-#define BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */
-#define BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */
-#define BFL_PALDO 0x02000000 /* Power topology uses PALDO */
-#define BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
+
+/* Board has gpio 9 controlling the PA */
+#define BFL_PACTRL 0x00000002
+/* Not ok to power down the chip pll and oscillator */
+#define BFL_NOPLLDOWN 0x00000020
+/* Board supports the Front End Module */
+#define BFL_FEM 0x00000800
+/* Board has an external LNA in 2.4GHz band */
+#define BFL_EXTLNA 0x00001000
+/* Board has no PA */
+#define BFL_NOPA 0x00010000
+/* Power topology uses BUCKBOOST */
+#define BFL_BUCKBOOST 0x00200000
+/* Board has FEM and switch to share antenna w/ BT */
+#define BFL_FEM_BT 0x00400000
+/* Power topology doesn't use CBUCK */
+#define BFL_NOCBUCK 0x00800000
+/* Power topology uses PALDO */
+#define BFL_PALDO 0x02000000
+/* Board has an external LNA in 5GHz band */
+#define BFL_EXTLNA_5GHz 0x10000000
/* boardflags2 */
-#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */
-#define BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
-#define BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */
-#define BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */
-#define BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */
-#define BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */
+
+/* Board has an external rxbb regulator */
+#define BFL2_RXBB_INT_REG_DIS 0x00000001
+/* Flag to implement alternative A-band PLL settings */
+#define BFL2_APLL_WAR 0x00000002
+/* Board permits enabling TX Power Control */
+#define BFL2_TXPWRCTRL_EN 0x00000004
+/* Board supports the 2X4 diversity switch */
+#define BFL2_2X4_DIV 0x00000008
+/* Board supports 5G band power gain */
+#define BFL2_5G_PWRGAIN 0x00000010
+/* Board overrides ASPM and Clkreq settings */
+#define BFL2_PCIEWAR_OVR 0x00000020
#define BFL2_LEGACY 0x00000080
-#define BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */
-#define BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */
-#define BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */
-#define BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */
-#define BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */
-#define BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */
+/* 4321mcm93 board uses Skyworks FEM */
+#define BFL2_SKWRKFEM_BRD 0x00000100
+/* Board has a WAR for clock-harmonic spurs */
+#define BFL2_SPUR_WAR 0x00000200
+/* Flag to narrow G-band PLL loop b/w */
+#define BFL2_GPLL_WAR 0x00000400
+/* Tx CCK pkts on Ant 0 only */
+#define BFL2_SINGLEANT_CCK 0x00001000
+/* WAR to reduce and avoid clock-harmonic spurs in 2G */
+#define BFL2_2G_SPUR_WAR 0x00002000
+/* Flag to widen G-band PLL loop b/w */
+#define BFL2_GPLL_WAR2 0x00010000
#define BFL2_IPALVLSHIFT_3P3 0x00020000
-#define BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */
-#define BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio "ON"
- * Most drivers will turn it off without this flag
- * to save power.
- */
+/* Use internal envelope detector for TX IQCAL */
+#define BFL2_INTERNDET_TXIQCAL 0x00040000
+/* Keep the buffered Xtal output from radio "ON". Most drivers will turn it
+ * off without this flag to save power. */
+#define BFL2_XTALBUFOUTEN 0x00080000
-/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
-#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
-#define BOARD_GPIO_12 0x1000 /* gpio 12 */
-#define BOARD_GPIO_13 0x2000 /* gpio 13 */
+/*
+ * board specific GPIO assignment, gpio 0-3 are also customer-configurable
+ * led
+ */
+
+/* bit 9 controls the PA on new 4306 boards */
+#define BOARD_GPIO_PACTRL 0x200
+#define BOARD_GPIO_12 0x1000
+#define BOARD_GPIO_13 0x2000
/* **** Core type/rev defaults **** */
#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27
@@ -152,30 +170,53 @@
#define PHYCONF_HAS(val) CONF_HAS(PHYTYPE, val)
#define PHYCONF_IS(val) CONF_IS(PHYTYPE, val)
-#define NREV_IS(var, val) (NCONF_HAS(val) && (NCONF_IS(val) || ((var) == (val))))
-#define NREV_GE(var, val) (NCONF_GE(val) && (!NCONF_LT(val) || ((var) >= (val))))
-#define NREV_GT(var, val) (NCONF_GT(val) && (!NCONF_LE(val) || ((var) > (val))))
-#define NREV_LT(var, val) (NCONF_LT(val) && (!NCONF_GE(val) || ((var) < (val))))
-#define NREV_LE(var, val) (NCONF_LE(val) && (!NCONF_GT(val) || ((var) <= (val))))
+#define NREV_IS(var, val) \
+ (NCONF_HAS(val) && (NCONF_IS(val) || ((var) == (val))))
+
+#define NREV_GE(var, val) \
+ (NCONF_GE(val) && (!NCONF_LT(val) || ((var) >= (val))))
+
+#define NREV_GT(var, val) \
+ (NCONF_GT(val) && (!NCONF_LE(val) || ((var) > (val))))
+
+#define NREV_LT(var, val) \
+ (NCONF_LT(val) && (!NCONF_GE(val) || ((var) < (val))))
+
+#define NREV_LE(var, val) \
+ (NCONF_LE(val) && (!NCONF_GT(val) || ((var) <= (val))))
+
+#define LCNREV_IS(var, val) \
+ (LCNCONF_HAS(val) && (LCNCONF_IS(val) || ((var) == (val))))
+
+#define LCNREV_GE(var, val) \
+ (LCNCONF_GE(val) && (!LCNCONF_LT(val) || ((var) >= (val))))
+
+#define LCNREV_GT(var, val) \
+ (LCNCONF_GT(val) && (!LCNCONF_LE(val) || ((var) > (val))))
+
+#define LCNREV_LT(var, val) \
+ (LCNCONF_LT(val) && (!LCNCONF_GE(val) || ((var) < (val))))
-#define LCNREV_IS(var, val) (LCNCONF_HAS(val) && (LCNCONF_IS(val) || ((var) == (val))))
-#define LCNREV_GE(var, val) (LCNCONF_GE(val) && (!LCNCONF_LT(val) || ((var) >= (val))))
-#define LCNREV_GT(var, val) (LCNCONF_GT(val) && (!LCNCONF_LE(val) || ((var) > (val))))
-#define LCNREV_LT(var, val) (LCNCONF_LT(val) && (!LCNCONF_GE(val) || ((var) < (val))))
-#define LCNREV_LE(var, val) (LCNCONF_LE(val) && (!LCNCONF_GT(val) || ((var) <= (val))))
+#define LCNREV_LE(var, val) \
+ (LCNCONF_LE(val) && (!LCNCONF_GT(val) || ((var) <= (val))))
-#define D11REV_IS(var, val) (D11CONF_HAS(val) && (D11CONF_IS(val) || ((var) == (val))))
-#define D11REV_GE(var, val) (D11CONF_GE(val) && (!D11CONF_LT(val) || ((var) >= (val))))
-#define D11REV_GT(var, val) (D11CONF_GT(val) && (!D11CONF_LE(val) || ((var) > (val))))
-#define D11REV_LT(var, val) (D11CONF_LT(val) && (!D11CONF_GE(val) || ((var) < (val))))
-#define D11REV_LE(var, val) (D11CONF_LE(val) && (!D11CONF_GT(val) || ((var) <= (val))))
+#define D11REV_IS(var, val) \
+ (D11CONF_HAS(val) && (D11CONF_IS(val) || ((var) == (val))))
-#define PHYTYPE_IS(var, val) (PHYCONF_HAS(val) && (PHYCONF_IS(val) || ((var) == (val))))
+#define D11REV_GE(var, val) \
+ (D11CONF_GE(val) && (!D11CONF_LT(val) || ((var) >= (val))))
-/* Finally, early-exit from switch case if anyone wants it... */
+#define D11REV_GT(var, val) \
+ (D11CONF_GT(val) && (!D11CONF_LE(val) || ((var) > (val))))
-#define CASECHECK(config, val) if (!(CONF_HAS(config, val))) break
-#define CASEMSK(config, mask) if (!(CONF_MSK(config, mask))) break
+#define D11REV_LT(var, val) \
+ (D11CONF_LT(val) && (!D11CONF_GE(val) || ((var) < (val))))
+
+#define D11REV_LE(var, val) \
+ (D11CONF_LE(val) && (!D11CONF_GT(val) || ((var) <= (val))))
+
+#define PHYTYPE_IS(var, val)\
+ (PHYCONF_HAS(val) && (PHYCONF_IS(val) || ((var) == (val))))
/* Set up PHYTYPE automatically: (depends on PHY_TYPE_X, from d11.h) */
@@ -203,116 +244,36 @@
* ********************************************************************
*/
-/*************************************************
- * Defaults for tunables (e.g. sizing constants)
- *
- * For each new tunable, add a member to the end
- * of struct brcms_tunables in brcms_c_pub.h to enable
- * runtime checks of tunable values. (Directly
- * using the macros in code invalidates ROM code)
- *
- * ***********************************************
- */
-#define NTXD 256 /* Max # of entries in Tx FIFO based on 4kb page size */
-#define NRXD 256 /* Max # of entries in Rx FIFO based on 4kb page size */
-#define NRXBUFPOST 32 /* try to keep this # rbufs posted to the chip */
-#define MAXSCB 32 /* Maximum SCBs in cache for STA */
-#define AMPDU_NUM_MPDU 16 /* max allowed number of mpdus in an ampdu (2 streams) */
-
-/* Count of packet callback structures. either of following
- * 1. Set to the number of SCBs since a STA
- * can queue up a rate callback for each IBSS STA it knows about, and an AP can
- * queue up an "are you there?" Null Data callback for each associated STA
- * 2. controlled by tunable config file
- */
-#define MAXPKTCB MAXSCB /* Max number of packet callbacks */
-
-/* NetBSD also needs to keep track of this */
-
-/* Number of BSS handled in ucode bcn/prb */
-#define BRCMS_MAX_UCODE_BSS (16)
-/* Number of BSS handled in sw bcn/prb */
-#define BRCMS_MAX_UCODE_BSS4 (4)
-/* max # BSS configs */
-#define BRCMS_MAXBSSCFG (1)
-/* max # available networks */
-#define MAXBSS 64
-/* data msg txq hiwat mark */
-#define BRCMS_DATAHIWAT 50
-#define BRCMS_AMPDUDATAHIWAT 255
-
-/* bounded rx loops */
-#define RXBND 8 /* max # frames to process in brcms_c_recv() */
-#define TXSBND 8 /* max # tx status to process in wlc_txstatus() */
-
-#define BAND_5G(bt) ((bt) == BRCM_BAND_5G)
-#define BAND_2G(bt) ((bt) == BRCM_BAND_2G)
-
#define BCMMSG(dev, fmt, args...) \
do { \
if (brcm_msg_level & LOG_TRACE_VAL) \
wiphy_err(dev, "%s: " fmt, __func__, ##args); \
} while (0)
-#define WL_ERROR_ON() (brcm_msg_level & LOG_ERROR_VAL)
-
-/* register access macros */
-#ifndef __BIG_ENDIAN
-#ifndef __mips__
-#define R_REG(r) \
- ({\
- sizeof(*(r)) == sizeof(u8) ? \
- readb((u8 *)(r)) : \
- sizeof(*(r)) == sizeof(u16) ? readw((u16 *)(r)) : \
- readl((u32 *)(r)); \
- })
-#else /* __mips__ */
-#define R_REG(r) \
- ({ \
- __typeof(*(r)) __osl_v; \
- __asm__ __volatile__("sync"); \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- __osl_v = readb((u8 *)(r)); \
- break; \
- case sizeof(u16): \
- __osl_v = readw((u16 *)(r)); \
- break; \
- case sizeof(u32): \
- __osl_v = \
- readl((u32 *)(r)); \
- break; \
- } \
- __asm__ __volatile__("sync"); \
- __osl_v; \
- })
-#endif /* __mips__ */
+/*
+ * Register access macros.
+ *
+ * These macro's take a pointer to the address to read as one of their
+ * arguments. The macro itself deduces the size of the IO transaction (u8, u16
+ * or u32). Advantage of this approach in combination with using a struct to
+ * define the registers in a register block, is that access size and access
+ * location are defined in only one spot. This reduces the risk of the
+ * programmer trying to use an unsupported transaction size on a register.
+ *
+ */
-#define W_REG(r, v) do { \
- switch (sizeof(*(r))) { \
- case sizeof(u8): \
- writeb((u8)(v), (u8 *)(r)); break; \
- case sizeof(u16): \
- writew((u16)(v), (u16 *)(r)); break; \
- case sizeof(u32): \
- writel((u32)(v), (u32 *)(r)); break; \
- }; \
- } while (0)
-#else /* __BIG_ENDIAN */
#define R_REG(r) \
({ \
__typeof(*(r)) __osl_v; \
switch (sizeof(*(r))) { \
case sizeof(u8): \
- __osl_v = \
- readb((u8 *)((r)^3)); \
+ __osl_v = readb((u8 __iomem *)(r)); \
break; \
case sizeof(u16): \
- __osl_v = \
- readw((u16 *)((r)^2)); \
+ __osl_v = readw((u16 __iomem *)(r)); \
break; \
case sizeof(u32): \
- __osl_v = readl((u32 *)(r)); \
+ __osl_v = readl((u32 __iomem *)(r)); \
break; \
} \
__osl_v; \
@@ -321,19 +282,18 @@ do { \
#define W_REG(r, v) do { \
switch (sizeof(*(r))) { \
case sizeof(u8): \
- writeb((u8)(v), \
- (u8 *)((r)^3)); break; \
+ writeb((u8)((v) & 0xFF), (u8 __iomem *)(r)); \
+ break; \
case sizeof(u16): \
- writew((u16)(v), \
- (u16 *)((r)^2)); break; \
+ writew((u16)((v) & 0xFFFF), (u16 __iomem *)(r)); \
+ break; \
case sizeof(u32): \
- writel((u32)(v), \
- (u32 *)(r)); break; \
+ writel((u32)(v), (u32 __iomem *)(r)); \
+ break; \
} \
} while (0)
-#endif /* __BIG_ENDIAN */
-#ifdef __mips__
+#ifdef CONFIG_BCM47XX
/*
* bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder
* transactions. As a fix, a read after write is performed on certain places
@@ -342,7 +302,7 @@ do { \
#define W_REG_FLUSH(r, v) ({ W_REG((r), (v)); (void)R_REG(r); })
#else
#define W_REG_FLUSH(r, v) W_REG((r), (v))
-#endif /* __mips__ */
+#endif /* CONFIG_BCM47XX */
#define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
#define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
@@ -351,12 +311,17 @@ do { \
W_REG((r), ((R_REG(r) & ~(mask)) | (val)))
/* multi-bool data type: set of bools, mbool is true if any is set */
-typedef u32 mbool;
-#define mboolset(mb, bit) ((mb) |= (bit)) /* set one bool */
-#define mboolclr(mb, bit) ((mb) &= ~(bit)) /* clear one bool */
-#define mboolisset(mb, bit) (((mb) & (bit)) != 0) /* true if one bool is set */
+
+/* set one bool */
+#define mboolset(mb, bit) ((mb) |= (bit))
+/* clear one bool */
+#define mboolclr(mb, bit) ((mb) &= ~(bit))
+/* true if one bool is set */
+#define mboolisset(mb, bit) (((mb) & (bit)) != 0)
#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
+#define CEIL(x, y) (((x) + ((y)-1)) / (y))
+
/* forward declarations */
struct wiphy;
struct ieee80211_sta;
@@ -364,34 +329,22 @@ struct ieee80211_tx_queue_params;
struct brcms_info;
struct brcms_c_info;
struct brcms_hardware;
-struct brcms_c_if;
-struct brcmu_iovar;
-struct brcmu_strbuf;
struct brcms_txq_info;
struct brcms_band;
struct dma_pub;
struct si_pub;
struct tx_status;
struct d11rxhdr;
-struct brcms_d11rxhdr;
struct txpwr_limits;
-struct brcms_phy;
-
-typedef volatile struct intctrlregs intctrlregs_t;
-typedef volatile struct pio2regs pio2regs_t;
-typedef volatile struct pio2regp pio2regp_t;
-typedef volatile struct pio4regs pio4regs_t;
-typedef volatile struct pio4regp pio4regp_t;
-typedef volatile struct fifo64 fifo64_t;
-typedef volatile struct d11regs d11regs_t;
-typedef volatile struct dma32diag dma32diag_t;
-typedef volatile struct dma64regs dma64regs_t;
-typedef struct brcms_rateset wlc_rateset_t;
-typedef u32 ratespec_t;
-typedef struct chanvec chanvec_t;
-typedef s32 fixed;
-typedef struct _cs32 cs32;
-typedef volatile union pmqreg pmqreg_t;
+
+/* iovar structure */
+struct brcmu_iovar {
+ const char *name; /* name for lookup and display */
+ u16 varid; /* id for switch */
+ u16 flags; /* driver-specific flag bits */
+ u16 type; /* base type of argument */
+ u16 minlen; /* min length for buffer vars */
+};
/* brcm_msg_level is a bit vector with defs in defs.h */
extern u32 brcm_msg_level;
diff --git a/drivers/staging/brcm80211/brcmsmac/ucode_loader.c b/drivers/staging/brcm80211/brcmsmac/ucode_loader.c
index bf733fb18ce1..80e3ccf865e3 100644
--- a/drivers/staging/brcm80211/brcmsmac/ucode_loader.c
+++ b/drivers/staging/brcm80211/brcmsmac/ucode_loader.c
@@ -37,79 +37,73 @@ enum {
D11UCODE_OVERSIGHT_BOMMINOR
};
-struct d11init *d11lcn0bsinitvals24;
-struct d11init *d11lcn0initvals24;
-struct d11init *d11lcn1bsinitvals24;
-struct d11init *d11lcn1initvals24;
-struct d11init *d11lcn2bsinitvals24;
-struct d11init *d11lcn2initvals24;
-struct d11init *d11n0absinitvals16;
-struct d11init *d11n0bsinitvals16;
-struct d11init *d11n0initvals16;
-u32 *bcm43xx_16_mimo;
-u32 bcm43xx_16_mimosz;
-u32 *bcm43xx_24_lcn;
-u32 bcm43xx_24_lcnsz;
-u32 *bcm43xx_bommajor;
-u32 *bcm43xx_bomminor;
-
-int brcms_ucode_data_init(struct brcms_info *wl)
+int brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode)
{
int rc;
+
rc = brcms_check_firmwares(wl);
rc = rc < 0 ? rc :
- brcms_ucode_init_buf(wl, (void **)&d11lcn0bsinitvals24,
+ brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0bsinitvals24,
D11LCN0BSINITVALS24);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&d11lcn0initvals24,
- D11LCN0INITVALS24);
- rc = rc < 0 ? rc :
- brcms_ucode_init_buf(wl, (void **)&d11lcn1bsinitvals24,
- D11LCN1BSINITVALS24);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&d11lcn1initvals24,
- D11LCN1INITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0initvals24,
+ D11LCN0INITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1bsinitvals24,
+ D11LCN1BSINITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1initvals24,
+ D11LCN1INITVALS24);
rc = rc < 0 ? rc :
- brcms_ucode_init_buf(wl, (void **)&d11lcn2bsinitvals24,
+ brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2bsinitvals24,
D11LCN2BSINITVALS24);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&d11lcn2initvals24,
- D11LCN2INITVALS24);
- rc = rc < 0 ? rc :
- brcms_ucode_init_buf(wl, (void **)&d11n0absinitvals16,
- D11N0ABSINITVALS16);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&d11n0bsinitvals16,
- D11N0BSINITVALS16);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&d11n0initvals16,
- D11N0INITVALS16);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&bcm43xx_16_mimo,
- D11UCODE_OVERSIGHT16_MIMO);
- rc = rc < 0 ? rc : brcms_ucode_init_uint(wl, &bcm43xx_16_mimosz,
- D11UCODE_OVERSIGHT16_MIMOSZ);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&bcm43xx_24_lcn,
- D11UCODE_OVERSIGHT24_LCN);
- rc = rc < 0 ? rc : brcms_ucode_init_uint(wl, &bcm43xx_24_lcnsz,
- D11UCODE_OVERSIGHT24_LCNSZ);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&bcm43xx_bommajor,
- D11UCODE_OVERSIGHT_BOMMAJOR);
- rc = rc < 0 ? rc : brcms_ucode_init_buf(wl, (void **)&bcm43xx_bomminor,
- D11UCODE_OVERSIGHT_BOMMINOR);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2initvals24,
+ D11LCN2INITVALS24);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0absinitvals16,
+ D11N0ABSINITVALS16);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0bsinitvals16,
+ D11N0BSINITVALS16);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0initvals16,
+ D11N0INITVALS16);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_16_mimo,
+ D11UCODE_OVERSIGHT16_MIMO);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_16_mimosz,
+ D11UCODE_OVERSIGHT16_MIMOSZ);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_24_lcn,
+ D11UCODE_OVERSIGHT24_LCN);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_24_lcnsz,
+ D11UCODE_OVERSIGHT24_LCNSZ);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bommajor,
+ D11UCODE_OVERSIGHT_BOMMAJOR);
+ rc = rc < 0 ?
+ rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bomminor,
+ D11UCODE_OVERSIGHT_BOMMINOR);
return rc;
}
-void brcms_ucode_data_free(void)
+void brcms_ucode_data_free(struct brcms_ucode *ucode)
{
- brcms_ucode_free_buf((void *)d11lcn0bsinitvals24);
- brcms_ucode_free_buf((void *)d11lcn0initvals24);
- brcms_ucode_free_buf((void *)d11lcn1bsinitvals24);
- brcms_ucode_free_buf((void *)d11lcn1initvals24);
- brcms_ucode_free_buf((void *)d11lcn2bsinitvals24);
- brcms_ucode_free_buf((void *)d11lcn2initvals24);
- brcms_ucode_free_buf((void *)d11n0absinitvals16);
- brcms_ucode_free_buf((void *)d11n0bsinitvals16);
- brcms_ucode_free_buf((void *)d11n0initvals16);
- brcms_ucode_free_buf((void *)bcm43xx_16_mimo);
- brcms_ucode_free_buf((void *)bcm43xx_24_lcn);
- brcms_ucode_free_buf((void *)bcm43xx_bommajor);
- brcms_ucode_free_buf((void *)bcm43xx_bomminor);
-
- return;
+ brcms_ucode_free_buf((void *)ucode->d11lcn0bsinitvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn0initvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn1bsinitvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn1initvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn2bsinitvals24);
+ brcms_ucode_free_buf((void *)ucode->d11lcn2initvals24);
+ brcms_ucode_free_buf((void *)ucode->d11n0absinitvals16);
+ brcms_ucode_free_buf((void *)ucode->d11n0bsinitvals16);
+ brcms_ucode_free_buf((void *)ucode->d11n0initvals16);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_16_mimo);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_24_lcn);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_bommajor);
+ brcms_ucode_free_buf((void *)ucode->bcm43xx_bomminor);
}
diff --git a/drivers/staging/brcm80211/brcmsmac/ucode_loader.h b/drivers/staging/brcm80211/brcmsmac/ucode_loader.h
index ca53deced7bf..18750a814b4f 100644
--- a/drivers/staging/brcm80211/brcmsmac/ucode_loader.h
+++ b/drivers/staging/brcm80211/brcmsmac/ucode_loader.h
@@ -13,6 +13,8 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef _BRCM_UCODE_H_
+#define _BRCM_UCODE_H_
#include "types.h" /* forward structure declarations */
@@ -21,32 +23,36 @@
#define UCODE_LOADER_API_VER 0
-struct d11init {
- u16 addr;
- u16 size;
- u32 value;
+struct d11init;
+
+struct brcms_ucode {
+ struct d11init *d11lcn0bsinitvals24;
+ struct d11init *d11lcn0initvals24;
+ struct d11init *d11lcn1bsinitvals24;
+ struct d11init *d11lcn1initvals24;
+ struct d11init *d11lcn2bsinitvals24;
+ struct d11init *d11lcn2initvals24;
+ struct d11init *d11n0absinitvals16;
+ struct d11init *d11n0bsinitvals16;
+ struct d11init *d11n0initvals16;
+ __le32 *bcm43xx_16_mimo;
+ size_t bcm43xx_16_mimosz;
+ __le32 *bcm43xx_24_lcn;
+ size_t bcm43xx_24_lcnsz;
+ u32 *bcm43xx_bommajor;
+ u32 *bcm43xx_bomminor;
};
-extern struct d11init *d11lcn0bsinitvals24;
-extern struct d11init *d11lcn0initvals24;
-extern struct d11init *d11lcn1bsinitvals24;
-extern struct d11init *d11lcn1initvals24;
-extern struct d11init *d11lcn2bsinitvals24;
-extern struct d11init *d11lcn2initvals24;
-extern struct d11init *d11n0absinitvals16;
-extern struct d11init *d11n0bsinitvals16;
-extern struct d11init *d11n0initvals16;
-extern u32 *bcm43xx_16_mimo;
-extern u32 bcm43xx_16_mimosz;
-extern u32 *bcm43xx_24_lcn;
-extern u32 bcm43xx_24_lcnsz;
-
-extern int brcms_ucode_data_init(struct brcms_info *wl);
-extern void brcms_ucode_data_free(void);
+extern int
+brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode);
+
+extern void brcms_ucode_data_free(struct brcms_ucode *ucode);
extern int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf,
unsigned int idx);
-extern int brcms_ucode_init_uint(struct brcms_info *wl, unsigned *data,
- unsigned int idx);
+extern int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes,
+ unsigned int idx);
extern void brcms_ucode_free_buf(void *);
extern int brcms_check_firmwares(struct brcms_info *wl);
+
+#endif /* _BRCM_UCODE_H_ */
diff --git a/drivers/staging/brcm80211/brcmutil/Makefile b/drivers/staging/brcm80211/brcmutil/Makefile
index 6403423c0212..45b808d747e2 100644
--- a/drivers/staging/brcm80211/brcmutil/Makefile
+++ b/drivers/staging/brcm80211/brcmutil/Makefile
@@ -20,8 +20,7 @@ ccflags-y := \
-Idrivers/staging/brcm80211/include
BRCMUTIL_OFILES := \
- utils.o \
- wifi.o
+ utils.o
MODULEPFX := brcmutil
diff --git a/drivers/staging/brcm80211/brcmutil/utils.c b/drivers/staging/brcm80211/brcmutil/utils.c
index 37b6b7797793..f27c48910827 100644
--- a/drivers/staging/brcm80211/brcmutil/utils.c
+++ b/drivers/staging/brcm80211/brcmutil/utils.c
@@ -15,6 +15,7 @@
*/
#include <linux/netdevice.h>
+#include <linux/module.h>
#include <brcmu_utils.h>
MODULE_AUTHOR("Broadcom Corporation");
@@ -219,7 +220,7 @@ EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
void
brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
- ifpkt_cb_t fn, void *arg)
+ bool (*fn)(struct sk_buff *, void *), void *arg)
{
struct pktq_prec *q;
struct sk_buff *p, *prev = NULL;
@@ -244,14 +245,13 @@ brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
}
}
- if (q->head == NULL) {
+ if (q->head == NULL)
q->tail = NULL;
- }
}
EXPORT_SYMBOL(brcmu_pktq_pflush);
void brcmu_pktq_flush(struct pktq *pq, bool dir,
- ifpkt_cb_t fn, void *arg)
+ bool (*fn)(struct sk_buff *, void *), void *arg)
{
int prec;
for (prec = 0; prec < pq->num_prec; prec++)
@@ -350,21 +350,6 @@ struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
}
EXPORT_SYMBOL(brcmu_pktq_mdeq);
-/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
-int brcmu_ether_atoe(char *p, u8 *ea)
-{
- int i = 0;
-
- for (;;) {
- ea[i++] = (char)simple_strtoul(p, &p, 16);
- if (!*p++ || i == 6)
- break;
- }
-
- return i == 6;
-}
-EXPORT_SYMBOL(brcmu_ether_atoe);
-
#if defined(BCMDBG)
/* pretty hex print a pkt buffer chain */
void brcmu_prpkt(const char *msg, struct sk_buff *p0)
@@ -380,232 +365,11 @@ void brcmu_prpkt(const char *msg, struct sk_buff *p0)
EXPORT_SYMBOL(brcmu_prpkt);
#endif /* defined(BCMDBG) */
-/* iovar table lookup */
-const struct brcmu_iovar *brcmu_iovar_lookup(const struct brcmu_iovar *table,
- const char *name)
-{
- const struct brcmu_iovar *vi;
- const char *lookup_name;
-
- /* skip any ':' delimited option prefixes */
- lookup_name = strrchr(name, ':');
- if (lookup_name != NULL)
- lookup_name++;
- else
- lookup_name = name;
-
- for (vi = table; vi->name; vi++) {
- if (!strcmp(vi->name, lookup_name))
- return vi;
- }
- /* ran to end of table */
-
- return NULL; /* var name not found */
-}
-EXPORT_SYMBOL(brcmu_iovar_lookup);
-
-int brcmu_iovar_lencheck(const struct brcmu_iovar *vi, void *arg, int len,
- bool set)
-{
- int bcmerror = 0;
-
- /* length check on io buf */
- switch (vi->type) {
- case IOVT_BOOL:
- case IOVT_INT8:
- case IOVT_INT16:
- case IOVT_INT32:
- case IOVT_UINT8:
- case IOVT_UINT16:
- case IOVT_UINT32:
- /* all integers are s32 sized args at the ioctl interface */
- if (len < (int)sizeof(int)) {
- bcmerror = -EOVERFLOW;
- }
- break;
-
- case IOVT_BUFFER:
- /* buffer must meet minimum length requirement */
- if (len < vi->minlen) {
- bcmerror = -EOVERFLOW;
- }
- break;
-
- case IOVT_VOID:
- if (!set) {
- /* Cannot return nil... */
- bcmerror = -ENOTSUPP;
- } else if (len) {
- /* Set is an action w/o parameters */
- bcmerror = -ENOBUFS;
- }
- break;
-
- default:
- /* unknown type for length check in iovar info */
- bcmerror = -ENOTSUPP;
- }
-
- return bcmerror;
-}
-EXPORT_SYMBOL(brcmu_iovar_lencheck);
-
-/*******************************************************************************
- * crc8
- *
- * Computes a crc8 over the input data using the polynomial:
- *
- * x^8 + x^7 +x^6 + x^4 + x^2 + 1
- *
- * The caller provides the initial value (either CRC8_INIT_VALUE
- * or the previous returned value) to allow for processing of
- * discontiguous blocks of data. When generating the CRC the
- * caller is responsible for complementing the final return value
- * and inserting it into the byte stream. When checking, a final
- * return value of CRC8_GOOD_VALUE indicates a valid CRC.
- *
- * Reference: Dallas Semiconductor Application Note 27
- * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
- * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
- * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
- *
- * ****************************************************************************
- */
-
-static const u8 crc8_table[256] = {
- 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
- 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
- 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
- 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
- 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
- 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
- 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
- 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
- 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
- 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
- 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
- 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
- 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
- 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
- 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
- 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
- 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
- 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
- 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
- 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
- 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
- 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
- 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
- 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
- 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
- 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
- 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
- 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
- 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
- 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
- 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
- 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
-};
-
-u8 brcmu_crc8(u8 *pdata, /* pointer to array of data to process */
- uint nbytes, /* number of input data bytes to process */
- u8 crc /* either CRC8_INIT_VALUE or previous return value */
- ) {
- /* loop over the buffer data */
- while (nbytes-- > 0)
- crc = crc8_table[(crc ^ *pdata++) & 0xff];
-
- return crc;
-}
-EXPORT_SYMBOL(brcmu_crc8);
-
+#if defined(BCMDBG)
/*
- * Traverse a string of 1-byte tag/1-byte length/variable-length value
- * triples, returning a pointer to the substring whose first element
- * matches tag
+ * print bytes formatted as hex to a string. return the resulting
+ * string length
*/
-struct brcmu_tlv *brcmu_parse_tlvs(void *buf, int buflen, uint key)
-{
- struct brcmu_tlv *elt;
- int totlen;
-
- elt = (struct brcmu_tlv *) buf;
- totlen = buflen;
-
- /* find tagged parameter */
- while (totlen >= 2) {
- int len = elt->len;
-
- /* validate remaining totlen */
- if ((elt->id == key) && (totlen >= (len + 2)))
- return elt;
-
- elt = (struct brcmu_tlv *) ((u8 *) elt + (len + 2));
- totlen -= (len + 2);
- }
-
- return NULL;
-}
-EXPORT_SYMBOL(brcmu_parse_tlvs);
-
-
-#if defined(BCMDBG)
-int
-brcmu_format_flags(const struct brcmu_bit_desc *bd, u32 flags, char *buf,
- int len)
-{
- int i;
- char *p = buf;
- char hexstr[16];
- int slen = 0, nlen = 0;
- u32 bit;
- const char *name;
-
- if (len < 2 || !buf)
- return 0;
-
- buf[0] = '\0';
-
- for (i = 0; flags != 0; i++) {
- bit = bd[i].bit;
- name = bd[i].name;
- if (bit == 0 && flags != 0) {
- /* print any unnamed bits */
- snprintf(hexstr, 16, "0x%X", flags);
- name = hexstr;
- flags = 0; /* exit loop */
- } else if ((flags & bit) == 0)
- continue;
- flags &= ~bit;
- nlen = strlen(name);
- slen += nlen;
- /* count btwn flag space */
- if (flags != 0)
- slen += 1;
- /* need NULL char as well */
- if (len <= slen)
- break;
- /* copy NULL char but don't count it */
- strncpy(p, name, nlen + 1);
- p += nlen;
- /* copy btwn flag space and NULL char */
- if (flags != 0)
- p += snprintf(p, 2, " ");
- len -= slen;
- }
-
- /* indicate the str was too short */
- if (flags != 0) {
- if (len < 2)
- p -= 2 - len; /* overwrite last char */
- p += snprintf(p, 2, ">");
- }
-
- return (int)(p - buf);
-}
-EXPORT_SYMBOL(brcmu_format_flags);
-
-/* print bytes formatted as hex to a string. return the resulting string length */
int brcmu_format_hex(char *str, const void *bytes, int len)
{
int i;
@@ -620,168 +384,3 @@ int brcmu_format_hex(char *str, const void *bytes, int len)
}
EXPORT_SYMBOL(brcmu_format_hex);
#endif /* defined(BCMDBG) */
-
-char *brcmu_chipname(uint chipid, char *buf, uint len)
-{
- const char *fmt;
-
- fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
- snprintf(buf, len, fmt, chipid);
- return buf;
-}
-EXPORT_SYMBOL(brcmu_chipname);
-
-uint brcmu_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
-{
- uint len;
-
- len = strlen(name) + 1;
-
- if ((len + datalen) > buflen)
- return 0;
-
- strncpy(buf, name, buflen);
-
- /* append data onto the end of the name string */
- memcpy(&buf[len], data, datalen);
- len += datalen;
-
- return len;
-}
-EXPORT_SYMBOL(brcmu_mkiovar);
-
-/* Quarter dBm units to mW
- * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
- * Table is offset so the last entry is largest mW value that fits in
- * a u16.
- */
-
-#define QDBM_OFFSET 153 /* Offset for first entry */
-#define QDBM_TABLE_LEN 40 /* Table size */
-
-/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
- * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
- */
-#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
-
-/* Largest mW value that will round down to the last table entry,
- * QDBM_OFFSET + QDBM_TABLE_LEN-1.
- * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) +
- * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
- */
-#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
-
-static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
-/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
-/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
-/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
-/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
-/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
-/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
-};
-
-u16 brcmu_qdbm_to_mw(u8 qdbm)
-{
- uint factor = 1;
- int idx = qdbm - QDBM_OFFSET;
-
- if (idx >= QDBM_TABLE_LEN) {
- /* clamp to max u16 mW value */
- return 0xFFFF;
- }
-
- /* scale the qdBm index up to the range of the table 0-40
- * where an offset of 40 qdBm equals a factor of 10 mW.
- */
- while (idx < 0) {
- idx += 40;
- factor *= 10;
- }
-
- /* return the mW value scaled down to the correct factor of 10,
- * adding in factor/2 to get proper rounding.
- */
- return (nqdBm_to_mW_map[idx] + factor / 2) / factor;
-}
-EXPORT_SYMBOL(brcmu_qdbm_to_mw);
-
-u8 brcmu_mw_to_qdbm(u16 mw)
-{
- u8 qdbm;
- int offset;
- uint mw_uint = mw;
- uint boundary;
-
- /* handle boundary case */
- if (mw_uint <= 1)
- return 0;
-
- offset = QDBM_OFFSET;
-
- /* move mw into the range of the table */
- while (mw_uint < QDBM_TABLE_LOW_BOUND) {
- mw_uint *= 10;
- offset -= 40;
- }
-
- for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) {
- boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] -
- nqdBm_to_mW_map[qdbm]) / 2;
- if (mw_uint < boundary)
- break;
- }
-
- qdbm += (u8) offset;
-
- return qdbm;
-}
-EXPORT_SYMBOL(brcmu_mw_to_qdbm);
-
-uint brcmu_bitcount(u8 *bitmap, uint length)
-{
- uint bitcount = 0, i;
- u8 tmp;
- for (i = 0; i < length; i++) {
- tmp = bitmap[i];
- while (tmp) {
- bitcount++;
- tmp &= (tmp - 1);
- }
- }
- return bitcount;
-}
-EXPORT_SYMBOL(brcmu_bitcount);
-
-/* Initialization of brcmu_strbuf structure */
-void brcmu_binit(struct brcmu_strbuf *b, char *buf, uint size)
-{
- b->origsize = b->size = size;
- b->origbuf = b->buf = buf;
-}
-EXPORT_SYMBOL(brcmu_binit);
-
-/* Buffer sprintf wrapper to guard against buffer overflow */
-int brcmu_bprintf(struct brcmu_strbuf *b, const char *fmt, ...)
-{
- va_list ap;
- int r;
-
- va_start(ap, fmt);
- r = vsnprintf(b->buf, b->size, fmt, ap);
-
- /* Non Ansi C99 compliant returns -1,
- * Ansi compliant return r >= b->size,
- * stdlib returns 0, handle all
- */
- if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
- b->size = 0;
- } else {
- b->size -= r;
- b->buf += r;
- }
-
- va_end(ap);
-
- return r;
-}
-EXPORT_SYMBOL(brcmu_bprintf);
diff --git a/drivers/staging/brcm80211/brcmutil/wifi.c b/drivers/staging/brcm80211/brcmutil/wifi.c
deleted file mode 100644
index b9ffe8682a27..000000000000
--- a/drivers/staging/brcm80211/brcmutil/wifi.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#include <brcmu_wifi.h>
-
-/*
- * Verify the chanspec is using a legal set of parameters, i.e. that the
- * chanspec specified a band, bw, ctl_sb and channel and that the
- * combination could be legal given any set of circumstances.
- * RETURNS: true is the chanspec is malformed, false if it looks good.
- */
-bool brcmu_chspec_malformed(chanspec_t chanspec)
-{
- /* must be 2G or 5G band */
- if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
- return true;
- /* must be 20 or 40 bandwidth */
- if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
- return true;
-
- /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */
- if (CHSPEC_IS20(chanspec)) {
- if (!CHSPEC_SB_NONE(chanspec))
- return true;
- } else {
- if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec))
- return true;
- }
-
- return false;
-}
-EXPORT_SYMBOL(brcmu_chspec_malformed);
-
-/*
- * This function returns the channel number that control traffic is being sent on, for legacy
- * channels this is just the channel number, for 40MHZ channels it is the upper or lowre 20MHZ
- * sideband depending on the chanspec selected
- */
-u8 brcmu_chspec_ctlchan(chanspec_t chspec)
-{
- u8 ctl_chan;
-
- /* Is there a sideband ? */
- if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
- return CHSPEC_CHANNEL(chspec);
- } else {
- /* we only support 40MHZ with sidebands */
- /* chanspec channel holds the centre frequency, use that and the
- * side band information to reconstruct the control channel number
- */
- if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) {
- /* control chan is the upper 20 MHZ SB of the 40MHZ channel */
- ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
- } else {
- /* control chan is the lower 20 MHZ SB of the 40MHZ channel */
- ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
- }
- }
-
- return ctl_chan;
-}
-EXPORT_SYMBOL(brcmu_chspec_ctlchan);
-
-/*
- * Return the channel number for a given frequency and base frequency.
- * The returned channel number is relative to the given base frequency.
- * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
- * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
- *
- * Frequency is specified in MHz.
- * The base frequency is specified as (start_factor * 500 kHz).
- * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
- * 2.4 GHz and 5 GHz bands.
- *
- * The returned channel will be in the range [1, 14] in the 2.4 GHz band
- * and [0, 200] otherwise.
- * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
- * frequency is not a 2.4 GHz channel, or if the frequency is not and even
- * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
- *
- * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
- */
-int brcmu_mhz2channel(uint freq, uint start_factor)
-{
- int ch = -1;
- uint base;
- int offset;
-
- /* take the default channel start frequency */
- if (start_factor == 0) {
- if (freq >= 2400 && freq <= 2500)
- start_factor = WF_CHAN_FACTOR_2_4_G;
- else if (freq >= 5000 && freq <= 6000)
- start_factor = WF_CHAN_FACTOR_5_G;
- }
-
- if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
- return 14;
-
- base = start_factor / 2;
-
- /* check that the frequency is in 1GHz range of the base */
- if ((freq < base) || (freq > base + 1000))
- return -1;
-
- offset = freq - base;
- ch = offset / 5;
-
- /* check that frequency is a 5MHz multiple from the base */
- if (offset != (ch * 5))
- return -1;
-
- /* restricted channel range check for 2.4G */
- if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
- return -1;
-
- return ch;
-}
-EXPORT_SYMBOL(brcmu_mhz2channel);
diff --git a/drivers/staging/brcm80211/include/brcmu_utils.h b/drivers/staging/brcm80211/include/brcmu_utils.h
index 2d54cc5f4b11..7d0f46e0eb95 100644
--- a/drivers/staging/brcm80211/include/brcmu_utils.h
+++ b/drivers/staging/brcm80211/include/brcmu_utils.h
@@ -19,18 +19,6 @@
#include <linux/skbuff.h>
-/* Buffer structure for collecting string-formatted data
-* using brcmu_bprintf() API.
-* Use brcmu_binit() to initialize before use
-*/
-
-struct brcmu_strbuf {
- char *buf; /* pointer to current position in origbuf */
- unsigned int size; /* current (residual) size in bytes */
- char *origbuf; /* unmodified pointer to orignal buffer */
- unsigned int origsize; /* unmodified orignal buffer size in bytes */
-};
-
/*
* Spin at most 'us' microseconds while 'exp' is true.
* Caller should explicitly test 'exp' when this completes
@@ -45,12 +33,36 @@ struct brcmu_strbuf {
}
/* osl multi-precedence packet queue */
-#ifndef PKTQ_LEN_DEFAULT
#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */
-#endif
-#ifndef PKTQ_MAX_PREC
#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */
-#endif
+
+#define BCME_STRLEN 64 /* Max string length for BCM errors */
+
+/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
+#define PKTBUFSZ 2048
+
+#ifndef setbit
+#ifndef NBBY /* the BSD family defines NBBY */
+#define NBBY 8 /* 8 bits per byte */
+#endif /* #ifndef NBBY */
+#define setbit(a, i) (((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
+#define clrbit(a, i) (((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
+#define isset(a, i) (((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
+#define isclr(a, i) ((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
+#endif /* setbit */
+
+#define NBITS(type) (sizeof(type) * 8)
+#define NBITVAL(nbits) (1 << (nbits))
+#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
+#define NBITMASK(nbits) MAXBITVAL(nbits)
+#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
+
+/* crc defines */
+#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
+#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
+
+/* 18-bytes of Ethernet address buffer length */
+#define ETHER_ADDR_STR_LEN 18
struct pktq_prec {
struct sk_buff *head; /* first packet to dequeue */
@@ -72,19 +84,37 @@ struct pktq {
struct pktq_prec q[PKTQ_MAX_PREC];
};
-/* fn(pkt, arg). return true if pkt belongs to if */
-typedef bool(*ifpkt_cb_t) (struct sk_buff *, void *);
-
/* operations on a specific precedence in packet queue */
-#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max))
-#define pktq_plen(pq, prec) ((pq)->q[prec].len)
-#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len)
-#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max)
-#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0)
+static inline int pktq_plen(struct pktq *pq, int prec)
+{
+ return pq->q[prec].len;
+}
-#define pktq_ppeek(pq, prec) ((pq)->q[prec].head)
-#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail)
+static inline int pktq_pavail(struct pktq *pq, int prec)
+{
+ return pq->q[prec].max - pq->q[prec].len;
+}
+
+static inline bool pktq_pfull(struct pktq *pq, int prec)
+{
+ return pq->q[prec].len >= pq->q[prec].max;
+}
+
+static inline bool pktq_pempty(struct pktq *pq, int prec)
+{
+ return pq->q[prec].len == 0;
+}
+
+static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec)
+{
+ return pq->q[prec].head;
+}
+
+static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec)
+{
+ return pq->q[prec].tail;
+}
extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
struct sk_buff *p);
@@ -98,8 +128,9 @@ extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len);
extern void brcmu_pkt_buf_free_skb(struct sk_buff *skb);
/* Empty the queue at particular precedence level */
+/* callback function fn(pkt, arg) returns true if pkt belongs to if */
extern void brcmu_pktq_pflush(struct pktq *pq, int prec,
- bool dir, ifpkt_cb_t fn, void *arg);
+ bool dir, bool (*fn)(struct sk_buff *, void *), void *arg);
/* operations on a set of precedences in packet queue */
@@ -109,25 +140,36 @@ extern struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
/* operations on packet queue as a whole */
-#define pktq_len(pq) ((int)(pq)->len)
-#define pktq_max(pq) ((int)(pq)->max)
-#define pktq_avail(pq) ((int)((pq)->max - (pq)->len))
-#define pktq_full(pq) ((pq)->len >= (pq)->max)
-#define pktq_empty(pq) ((pq)->len == 0)
+static inline int pktq_len(struct pktq *pq)
+{
+ return (int)pq->len;
+}
+
+static inline int pktq_max(struct pktq *pq)
+{
+ return (int)pq->max;
+}
+
+static inline int pktq_avail(struct pktq *pq)
+{
+ return (int)(pq->max - pq->len);
+}
+
+static inline bool pktq_full(struct pktq *pq)
+{
+ return pq->len >= pq->max;
+}
-/* operations for single precedence queues */
-#define pktenq(pq, p) brcmu_pktq_penq(((struct pktq *)pq), 0, (p))
-#define pktenq_head(pq, p)\
- brcmu_pktq_penq_head(((struct pktq *)pq), 0, (p))
-#define pktdeq(pq) brcmu_pktq_pdeq(((struct pktq *)pq), 0)
-#define pktdeq_tail(pq) brcmu_pktq_pdeq_tail(((struct pktq *)pq), 0)
-#define pktqinit(pq, len) brcmu_pktq_init(((struct pktq *)pq), 1, len)
+static inline bool pktq_empty(struct pktq *pq)
+{
+ return pq->len == 0;
+}
extern void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len);
/* prec_out may be NULL if caller is not interested in return value */
extern struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out);
extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
- ifpkt_cb_t fn, void *arg);
+ bool (*fn)(struct sk_buff *, void *), void *arg);
/* externs */
/* packet */
@@ -135,9 +177,6 @@ extern uint brcmu_pktfrombuf(struct sk_buff *p,
uint offset, int len, unsigned char *buf);
extern uint brcmu_pkttotlen(struct sk_buff *p);
-/* ethernet address */
-extern int brcmu_ether_atoe(char *p, u8 *ea);
-
/* ip address */
struct ipv4_addr;
@@ -147,155 +186,10 @@ extern void brcmu_prpkt(const char *msg, struct sk_buff *p0);
#define brcmu_prpkt(a, b)
#endif /* BCMDBG */
-/* Support for sharing code across in-driver iovar implementations.
- * The intent is that a driver use this structure to map iovar names
- * to its (private) iovar identifiers, and the lookup function to
- * find the entry. Macros are provided to map ids and get/set actions
- * into a single number space for a switch statement.
- */
-
-/* iovar structure */
-struct brcmu_iovar {
- const char *name; /* name for lookup and display */
- u16 varid; /* id for switch */
- u16 flags; /* driver-specific flag bits */
- u16 type; /* base type of argument */
- u16 minlen; /* min length for buffer vars */
-};
-
-/* varid definitions are per-driver, may use these get/set bits */
-
-/* IOVar action bits for id mapping */
-#define IOV_GET 0 /* Get an iovar */
-#define IOV_SET 1 /* Set an iovar */
-
-/* Varid to actionid mapping */
-#define IOV_GVAL(id) ((id)*2)
-#define IOV_SVAL(id) (((id)*2)+IOV_SET)
-#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET)
-#define IOV_ID(actionid) (actionid >> 1)
-
-extern const struct
-brcmu_iovar *brcmu_iovar_lookup(const struct brcmu_iovar *table,
- const char *name);
-extern int brcmu_iovar_lencheck(const struct brcmu_iovar *table, void *arg,
- int len, bool set);
-
-/* Base type definitions */
-#define IOVT_VOID 0 /* no value (implictly set only) */
-#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */
-#define IOVT_INT8 2 /* integer values are range-checked */
-#define IOVT_UINT8 3 /* unsigned int 8 bits */
-#define IOVT_INT16 4 /* int 16 bits */
-#define IOVT_UINT16 5 /* unsigned int 16 bits */
-#define IOVT_INT32 6 /* int 32 bits */
-#define IOVT_UINT32 7 /* unsigned int 32 bits */
-#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */
-#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER)
-
-/* ** driver/apps-shared section ** */
-
-#define BCME_STRLEN 64 /* Max string length for BCM errors */
-
-#ifndef ABS
-#define ABS(a) (((a) < 0) ? -(a) : (a))
-#endif /* ABS */
-
-#define CEIL(x, y) (((x) + ((y)-1)) / (y))
-#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
-
-/* map physical to virtual I/O */
-#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), \
- (unsigned long)(size))
-
-/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
-#define PKTBUFSZ 2048
-
-#define OSL_SYSUPTIME() ((u32)jiffies * (1000 / HZ))
-
-#ifndef setbit
-#ifndef NBBY /* the BSD family defines NBBY */
-#define NBBY 8 /* 8 bits per byte */
-#endif /* #ifndef NBBY */
-#define setbit(a, i) (((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
-#define clrbit(a, i) (((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
-#define isset(a, i) (((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
-#define isclr(a, i) ((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
-#endif /* setbit */
-
-#define NBITS(type) (sizeof(type) * 8)
-#define NBITVAL(nbits) (1 << (nbits))
-#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
-#define NBITMASK(nbits) MAXBITVAL(nbits)
-#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
-
-/* basic mux operation - can be optimized on several architectures */
-#define MUX(pred, true, false) ((pred) ? (true) : (false))
-
-/* modulo inc/dec - assumes x E [0, bound - 1] */
-#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1)
-#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
-
-/* modulo inc/dec, bound = 2^k */
-#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
-#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
-
-/* modulo add/sub - assumes x, y E [0, bound - 1] */
-#define MODADD(x, y, bound) \
- MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y))
-#define MODSUB(x, y, bound) \
- MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y))
-
-/* module add/sub, bound = 2^k */
-#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
-#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
-
-/* crc defines */
-#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */
-#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */
-#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
-#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
-
-/* brcmu_format_flags() bit description structure */
-struct brcmu_bit_desc {
- u32 bit;
- const char *name;
-};
-
-/* tag_ID/length/value_buffer tuple */
-struct brcmu_tlv {
- u8 id;
- u8 len;
- u8 data[1];
-};
-
-#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */
-
/* externs */
-/* crc */
-extern u8 brcmu_crc8(u8 *p, uint nbytes, u8 crc);
-
/* format/print */
#if defined(BCMDBG)
-extern int brcmu_format_flags(const struct brcmu_bit_desc *bd, u32 flags,
- char *buf, int len);
extern int brcmu_format_hex(char *str, const void *bytes, int len);
#endif
-extern char *brcmu_chipname(uint chipid, char *buf, uint len);
-
-extern struct brcmu_tlv *brcmu_parse_tlvs(void *buf, int buflen,
- uint key);
-
-/* power conversion */
-extern u16 brcmu_qdbm_to_mw(u8 qdbm);
-extern u8 brcmu_mw_to_qdbm(u16 mw);
-
-extern void brcmu_binit(struct brcmu_strbuf *b, char *buf, uint size);
-extern int brcmu_bprintf(struct brcmu_strbuf *b, const char *fmt, ...);
-
-extern uint brcmu_mkiovar(char *name, char *data, uint datalen,
- char *buf, uint len);
-extern uint brcmu_bitcount(u8 *bitmap, uint bytelength);
-
#endif /* _BRCMU_UTILS_H_ */
diff --git a/drivers/staging/brcm80211/include/brcmu_wifi.h b/drivers/staging/brcm80211/include/brcmu_wifi.h
index fde592bd9177..f10d30274c23 100644
--- a/drivers/staging/brcm80211/include/brcmu_wifi.h
+++ b/drivers/staging/brcm80211/include/brcmu_wifi.h
@@ -20,8 +20,10 @@
#include <linux/if_ether.h> /* for ETH_ALEN */
#include <linux/ieee80211.h> /* for WLAN_PMKID_LEN */
-/* A chanspec holds the channel number, band, bandwidth and control sideband */
-typedef u16 chanspec_t;
+/*
+ * A chanspec (u16) holds the channel number, band, bandwidth and control
+ * sideband
+ */
/* channel defines */
#define CH_UPPER_SB 0x01
@@ -29,13 +31,20 @@ typedef u16 chanspec_t;
#define CH_EWA_VALID 0x04
#define CH_20MHZ_APART 4
#define CH_10MHZ_APART 2
-#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
+#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */
#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */
#define BRCM_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL /* legacy define */
-#define MAXCHANNEL 224 /* max # supported channels. The max channel no is 216,
- * this is that + 1 rounded up to a multiple of NBBY (8).
- * DO NOT MAKE it > 255: channels are u8's all over
- */
+
+/* bandstate array indices */
+#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */
+#define BAND_5G_INDEX 1 /* wlc->bandstate[x] index */
+
+/*
+ * max # supported channels. The max channel no is 216, this is that + 1
+ * rounded up to a multiple of NBBY (8). DO NOT MAKE it > 255: channels are
+ * u8's all over
+*/
+#define MAXCHANNEL 224
#define WL_CHANSPEC_CHAN_MASK 0x00ff
#define WL_CHANSPEC_CHAN_SHIFT 0
@@ -63,58 +72,78 @@ typedef u16 chanspec_t;
#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
-/* channel defines */
-#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0)
-#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
- ((channel) + CH_10MHZ_APART) : 0)
-#define CHSPEC_BANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : \
- BAND_2G_INDEX)
-#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \
- WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \
- WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
-#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \
- ((channel) + CH_20MHZ_APART) : 0)
-#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
- ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \
- ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \
- WL_CHANSPEC_BAND_5G))
#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
-#ifdef WL11N_20MHZONLY
+#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
+#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
-#define CHSPEC_CTL_SB(chspec) WL_CHANSPEC_CTL_SB_NONE
-#define CHSPEC_BW(chspec) WL_CHANSPEC_BW_20
-#define CHSPEC_IS10(chspec) 0
-#define CHSPEC_IS20(chspec) 1
-#ifndef CHSPEC_IS40
-#define CHSPEC_IS40(chspec) 0
-#endif
+#define CHSPEC_IS10(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
-#else /* !WL11N_20MHZONLY */
+#define CHSPEC_IS20(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
-#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK)
-#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK)
-#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
-#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
#ifndef CHSPEC_IS40
-#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
+#define CHSPEC_IS40(chspec) \
+ (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
#endif
-#endif /* !WL11N_20MHZONLY */
+#define CHSPEC_IS5G(chspec) \
+ (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
+
+#define CHSPEC_IS2G(chspec) \
+ (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
+
+#define CHSPEC_SB_NONE(chspec) \
+ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE)
+
+#define CHSPEC_SB_UPPER(chspec) \
+ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER)
+
+#define CHSPEC_SB_LOWER(chspec) \
+ (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER)
+
+#define CHSPEC_CTL_CHAN(chspec) \
+ ((CHSPEC_SB_LOWER(chspec)) ? \
+ (lower_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \
+ (upper_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK))))
-#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
-#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
-#define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE)
-#define CHSPEC_SB_UPPER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER)
-#define CHSPEC_SB_LOWER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER)
-#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \
- (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \
- (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))))
#define CHSPEC2BAND(chspec) (CHSPEC_IS5G(chspec) ? BRCM_BAND_5G : BRCM_BAND_2G)
#define CHANSPEC_STR_LEN 8
+static inline int lower_20_sb(int channel)
+{
+ return channel > CH_10MHZ_APART ? (channel - CH_10MHZ_APART) : 0;
+}
+
+static inline int upper_20_sb(int channel)
+{
+ return (channel < (MAXCHANNEL - CH_10MHZ_APART)) ?
+ channel + CH_10MHZ_APART : 0;
+}
+
+static inline int chspec_bandunit(u16 chspec)
+{
+ return CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX;
+}
+
+static inline u16 ch20mhz_chspec(int channel)
+{
+ u16 rc = channel <= CH_MAX_2G_CHANNEL ?
+ WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G;
+
+ return (u16)((u16)channel | WL_CHANSPEC_BW_20 |
+ WL_CHANSPEC_CTL_SB_NONE | rc);
+}
+
+static inline int next_20mhz_chan(int channel)
+{
+ return channel < (MAXCHANNEL - CH_20MHZ_APART) ?
+ channel + CH_20MHZ_APART : 0;
+}
+
/* defined rate in 500kbps */
#define BRCM_MAXRATE 108 /* in 500kbps units */
#define BRCM_RATE_1M 2 /* in 500kbps units */
@@ -134,43 +163,10 @@ typedef u16 chanspec_t;
#define MCSSET_LEN 16
-#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0)
-
-/*
- * Verify the chanspec is using a legal set of parameters, i.e. that the
- * chanspec specified a band, bw, ctl_sb and channel and that the
- * combination could be legal given any set of circumstances.
- * RETURNS: true is the chanspec is malformed, false if it looks good.
- */
-extern bool brcmu_chspec_malformed(chanspec_t chanspec);
-
-/*
- * This function returns the channel number that control traffic is being sent on, for legacy
- * channels this is just the channel number, for 40MHZ channels it is the upper or lowre 20MHZ
- * sideband depending on the chanspec selected
- */
-extern u8 brcmu_chspec_ctlchan(chanspec_t chspec);
-
-/*
- * Return the channel number for a given frequency and base frequency.
- * The returned channel number is relative to the given base frequency.
- * If the given base frequency is zero, a base frequency of 5 GHz is assumed for
- * frequencies from 5 - 6 GHz, and 2.407 GHz is assumed for 2.4 - 2.5 GHz.
- *
- * Frequency is specified in MHz.
- * The base frequency is specified as (start_factor * 500 kHz).
- * Constants WF_CHAN_FACTOR_2_4_G, WF_CHAN_FACTOR_5_G are defined for
- * 2.4 GHz and 5 GHz bands.
- *
- * The returned channel will be in the range [1, 14] in the 2.4 GHz band
- * and [0, 200] otherwise.
- * -1 is returned if the start_factor is WF_CHAN_FACTOR_2_4_G and the
- * frequency is not a 2.4 GHz channel, or if the frequency is not and even
- * multiple of 5 MHz from the base frequency to the base plus 1 GHz.
- *
- * Reference 802.11 REVma, section 17.3.8.3, and 802.11B section 18.4.6.2
- */
-extern int brcmu_mhz2channel(uint freq, uint start_factor);
+static inline bool ac_bitmap_tst(u8 bitmap, int prec)
+{
+ return (bitmap & (1 << (prec))) != 0;
+}
/* Enumerate crypto algorithms */
#define CRYPTO_ALGO_OFF 0
@@ -183,11 +179,13 @@ extern int brcmu_mhz2channel(uint freq, uint start_factor);
#define CRYPTO_ALGO_NALG 7
/* wireless security bitvec */
+
#define WEP_ENABLED 0x0001
#define TKIP_ENABLED 0x0002
#define AES_ENABLED 0x0004
#define WSEC_SWFLAG 0x0008
-#define SES_OW_ENABLED 0x0040 /* to go into transition mode without setting wep */
+/* to go into transition mode without setting wep */
+#define SES_OW_ENABLED 0x0040
/* WPA authentication mode bitvec */
#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */
@@ -196,7 +194,7 @@ extern int brcmu_mhz2channel(uint freq, uint start_factor);
#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */
#define WPA_AUTH_RESERVED1 0x0008
#define WPA_AUTH_RESERVED2 0x0010
- /* #define WPA_AUTH_8021X 0x0020 *//* 802.1x, reserved */
+
#define WPA2_AUTH_RESERVED1 0x0020
#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */
#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */
@@ -218,26 +216,24 @@ extern int brcmu_mhz2channel(uint freq, uint start_factor);
#define HT_CAP_RX_STBC_NO 0x0
#define HT_CAP_RX_STBC_ONE_STREAM 0x1
-typedef struct _pmkid {
+struct pmkid {
u8 BSSID[ETH_ALEN];
u8 PMKID[WLAN_PMKID_LEN];
-} pmkid_t;
+};
-typedef struct _pmkid_list {
- u32 npmkid;
- pmkid_t pmkid[1];
-} pmkid_list_t;
+struct pmkid_list {
+ __le32 npmkid;
+ struct pmkid pmkid[1];
+};
-typedef struct _pmkid_cand {
+struct pmkid_cand {
u8 BSSID[ETH_ALEN];
u8 preauth;
-} pmkid_cand_t;
+};
-typedef struct _pmkid_cand_list {
+struct pmkid_cand_list {
u32 npmkid_cand;
- pmkid_cand_t pmkid_cand[1];
-} pmkid_cand_list_t;
-
-typedef u8 ac_bitmap_t;
+ struct pmkid_cand pmkid_cand[1];
+};
#endif /* _BRCMU_WIFI_H_ */
diff --git a/drivers/staging/brcm80211/include/chipcommon.h b/drivers/staging/brcm80211/include/chipcommon.h
index 296582aced69..fefabc39e646 100644
--- a/drivers/staging/brcm80211/include/chipcommon.h
+++ b/drivers/staging/brcm80211/include/chipcommon.h
@@ -19,7 +19,7 @@
#include "defs.h" /* for PAD macro */
-typedef volatile struct {
+struct chipcregs {
u32 chipid; /* 0x0 */
u32 capabilities;
u32 corecontrol; /* corerev >= 1 */
@@ -214,7 +214,7 @@ typedef volatile struct {
u32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */
u32 PAD[100];
u16 sromotp[768];
-} chipcregs_t;
+};
/* chipid */
#define CID_ID_MASK 0x0000ffff /* Chip Id mask */
@@ -231,7 +231,8 @@ typedef volatile struct {
#define CC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */
#define CC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
#define CC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */
-#define CC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */
+/* UARTs are driven by internal divided clock */
+#define CC_CAP_UINTCLK 0x00000008
#define CC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */
#define CC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */
#define CC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */
@@ -248,10 +249,12 @@ typedef volatile struct {
#define CC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */
#define CC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */
#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */
-#define CC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */
+/* Nand flash present, rev >= 35 */
+#define CC_CAP_NFLASH 0x80000000
#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */
-#define CC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */
+/* GSIO (spi/i2c) present, rev >= 37 */
+#define CC_CAP2_GSIO 0x00000002
/* pmucapabilities */
#define PCAP_REV_MASK 0x000000ff
diff --git a/drivers/staging/brcm80211/include/defs.h b/drivers/staging/brcm80211/include/defs.h
index 8b3e17dec150..1e5f310af1e7 100644
--- a/drivers/staging/brcm80211/include/defs.h
+++ b/drivers/staging/brcm80211/include/defs.h
@@ -27,14 +27,8 @@
#define USB_BUS 5
#define SPI_BUS 6
-#ifndef OFF
#define OFF 0
-#endif
-
-#ifndef ON
#define ON 1 /* ON = 1 */
-#endif
-
#define AUTO (-1) /* Auto = -1 */
/*
@@ -54,27 +48,23 @@
#define WL_NUMRATES 16 /* max # of rates in a rateset */
-typedef struct wl_rateset {
- u32 count; /* # rates in this set */
- u8 rates[WL_NUMRATES]; /* rates in 500kbps units w/hi bit set if basic */
-} wl_rateset_t;
-
#define BRCM_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */
-#define BRCM_SET_CHANNEL 30
-#define BRCM_SET_SRL 32
-#define BRCM_SET_LRL 34
+#define BRCM_SET_CHANNEL 30
+#define BRCM_SET_SRL 32
+#define BRCM_SET_LRL 34
+#define BRCM_SET_BCNPRD 76
-#define BRCM_SET_RATESET 72
-#define BRCM_SET_BCNPRD 76
-#define BRCM_GET_CURR_RATESET 114 /* current rateset */
-#define BRCM_GET_PHYLIST 180
+#define BRCM_GET_CURR_RATESET 114 /* current rateset */
+#define BRCM_GET_PHYLIST 180
/* Bit masks for radio disabled status - returned by WL_GET_RADIO */
+
#define WL_RADIO_SW_DISABLE (1<<0)
#define WL_RADIO_HW_DISABLE (1<<1)
#define WL_RADIO_MPC_DISABLE (1<<2)
-#define WL_RADIO_COUNTRY_DISABLE (1<<3) /* some countries don't support any channel */
+/* some countries don't support any channel */
+#define WL_RADIO_COUNTRY_DISABLE (1<<3)
/* Override bit for SET_TXPWR. if set, ignore other level limits */
#define WL_TXPWR_OVERRIDE (1U<<31)
@@ -100,7 +90,9 @@ typedef struct wl_rateset {
/*
* Sonics Configuration Space Registers.
*/
-#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */
+
+/* core sbconfig regs are top 256bytes of regs */
+#define SBCONFIGOFF 0xf00
/* cpp contortions to concatenate w/arg prescan */
#ifndef PAD
diff --git a/drivers/staging/brcm80211/include/soc.h b/drivers/staging/brcm80211/include/soc.h
index 6e5a705c4937..4fcb956ad9e0 100644
--- a/drivers/staging/brcm80211/include/soc.h
+++ b/drivers/staging/brcm80211/include/soc.h
@@ -17,11 +17,7 @@
#ifndef _BRCM_SOC_H
#define _BRCM_SOC_H
-#ifdef SI_ENUM_BASE_VARIABLE
-#define SI_ENUM_BASE (sii->pub.si_enum_base)
-#else
#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
-#endif /* SI_ENUM_BASE_VARIABLE */
/* core codes */
#define NODEV_CORE_ID 0x700 /* Invalid coreid */
@@ -81,9 +77,8 @@
#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */
#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */
#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */
-#define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all
- * unused address ranges
- */
+/* Default component, in ai chips it maps all unused address ranges */
+#define DEF_AI_COMP 0xfff
/* Common core control flags */
#define SICF_BIST_EN 0x8000
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 72258e8c64ca..be3c392d83b3 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -353,7 +353,6 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
if(err < 0)
dev_err(nvec->dev, "couldn't request gpio\n");
- tegra_gpio_enable(nvec->gpio);
gpio_direction_output(nvec->gpio, 1);
gpio_set_value(nvec->gpio, 1);
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 438af89db55e..efb9c27efbf3 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
obj-$(CONFIG_SERIAL_S5PV210) += s5pv210.o
+CFLAGS_tegra_hsuart.o = -Werror
obj-$(CONFIG_SERIAL_TEGRA) += tegra_hsuart.o
obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
diff --git a/drivers/tty/serial/tegra_hsuart.c b/drivers/tty/serial/tegra_hsuart.c
index ea20de6ebb41..b2fa281492a7 100644
--- a/drivers/tty/serial/tegra_hsuart.c
+++ b/drivers/tty/serial/tegra_hsuart.c
@@ -3,7 +3,7 @@
*
* High-speed serial driver for NVIDIA Tegra SoCs
*
- * 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 the
@@ -59,6 +59,8 @@
#define UART_MCR_CTS_EN 0x20
#define UART_LSR_ANY (UART_LSR_OE | UART_LSR_BI | \
UART_LSR_PE | UART_LSR_FE)
+#define TEGRA_UART_IRDA_CSR 0x8
+#define TEGRA_UART_SIR_ENABLED 0x80
#define TX_FORCE_PIO 0
#define RX_FORCE_PIO 0
@@ -92,6 +94,12 @@ const int dma_req_sel[] = {
struct tegra_uart_port {
struct uart_port uport;
char port_name[32];
+ bool is_irda;
+ int (*irda_init)(void);
+ void (*irda_start)(void);
+ int (*irda_mode_switch)(int);
+ void (*irda_shutdown)(void);
+ void (*irda_remove)(void);
/* Module info */
unsigned long size;
@@ -130,6 +138,8 @@ static void tegra_set_baudrate(struct tegra_uart_port *t, unsigned int baud);
static void do_handle_rx_pio(struct tegra_uart_port *t);
static void do_handle_rx_dma(struct tegra_uart_port *t);
static void set_rts(struct tegra_uart_port *t, bool active);
+static void tegra_start_rx(struct uart_port *u);
+static void tegra_stop_rx(struct uart_port *u);
static inline u8 uart_readb(struct tegra_uart_port *t, unsigned long reg)
{
@@ -224,6 +234,8 @@ static void tegra_start_next_tx(struct tegra_uart_port *t)
{
unsigned long tail;
unsigned long count;
+ unsigned long lsr;
+ struct uart_port *u = &t->uport;
struct circ_buf *xmit;
@@ -235,8 +247,22 @@ static void tegra_start_next_tx(struct tegra_uart_port *t)
dev_vdbg(t->uport.dev, "+%s %lu %d\n", __func__, count,
t->tx_in_progress);
- if (count == 0)
+ if (count == 0) {
+ if (t->is_irda) {
+ do {
+ lsr = uart_readb(t, UART_LSR);
+ if (lsr & UART_LSR_TEMT)
+ break;
+ } while (1);
+ tegra_start_rx(u);
+ }
goto out;
+ }
+
+ if (t->is_irda) {
+ if (t->rx_in_progress)
+ tegra_stop_rx(u);
+ }
if (!t->use_tx_dma || count < TEGRA_UART_MIN_DMA)
tegra_start_pio_tx(t, count);
@@ -599,6 +625,42 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
}
}
+static void tegra_start_rx(struct uart_port *u)
+{
+ struct tegra_uart_port *t;
+ unsigned char ier;
+
+ t = container_of(u, struct tegra_uart_port, uport);
+
+ if (t->rts_active)
+ set_rts(t, true);
+
+ if (!t->rx_in_progress) {
+ wait_sym_time(t, 1); /* wait a character interval */
+
+ /* Clear the received Bytes from FIFO */
+ tegra_fifo_reset(t, UART_FCR_CLEAR_RCVR);
+ uart_readb(t, UART_LSR);
+ ier = 0;
+ ier |= (UART_IER_RLSI | UART_IER_RTOIE);
+ if (t->use_rx_dma)
+ ier |= UART_IER_EORD;
+ else
+ ier |= UART_IER_RDI;
+ t->ier_shadow |= ier;
+ uart_writeb(t, t->ier_shadow, UART_IER);
+
+ t->rx_in_progress = 1;
+
+ if (t->use_rx_dma && t->rx_dma)
+ tegra_dma_enqueue_req(t->rx_dma, &t->rx_dma_req);
+
+ tty_flip_buffer_push(u->state->port.tty);
+ }
+
+ return;
+}
+
static void tegra_stop_rx(struct uart_port *u)
{
struct tegra_uart_port *t;
@@ -705,6 +767,7 @@ static void tegra_uart_free_rx_dma(struct tegra_uart_port *t)
static int tegra_uart_hw_init(struct tegra_uart_port *t)
{
unsigned char ier;
+ unsigned char sir;
dev_vdbg(t->uport.dev, "+tegra_uart_hw_init\n");
@@ -800,6 +863,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *t)
t->ier_shadow = ier;
uart_writeb(t, ier, UART_IER);
+ /*
+ * Tegra UART controller also support SIR PHY
+ * Enabled IRDA will transmit each zero bit as a short IR pulse.
+ */
+ if (t->is_irda) {
+ dev_vdbg(t->uport.dev, "SIR enabled\n");
+ sir = TEGRA_UART_SIR_ENABLED;
+ uart_writeb(t, sir, TEGRA_UART_IRDA_CSR);
+ }
+
t->uart_state = TEGRA_UART_OPENED;
dev_vdbg(t->uport.dev, "-tegra_uart_hw_init\n");
return 0;
@@ -894,6 +967,9 @@ static int tegra_startup(struct uart_port *u)
if (ret)
goto fail;
+ if (t->is_irda && t->irda_start)
+ t->irda_start();
+
pdata = u->dev->platform_data;
if (pdata && pdata->is_loopback)
t->mcr_shadow |= UART_MCR_LOOP;
@@ -920,6 +996,9 @@ static void tegra_shutdown(struct uart_port *u)
t = container_of(u, struct tegra_uart_port, uport);
dev_vdbg(u->dev, "+tegra_shutdown\n");
+ if (t->is_irda && t->irda_shutdown)
+ t->irda_shutdown();
+
tegra_uart_hw_deinit(t);
t->rx_in_progress = 0;
@@ -1418,6 +1497,7 @@ static int __init tegra_uart_probe(struct platform_device *pdev)
{
struct tegra_uart_port *t;
struct uart_port *u;
+ struct tegra_uart_platform_data *pdata;
struct resource *resource;
int ret;
char name[64];
@@ -1439,6 +1519,20 @@ static int __init tegra_uart_probe(struct platform_device *pdev)
u->type = PORT_TEGRA;
u->fifosize = 32;
+ pdata = u->dev->platform_data;
+ if (pdata && pdata->is_irda) {
+ dev_info(&pdev->dev, "Initialized UART %d as SIR PHY\n",
+ u->line);
+ t->is_irda = pdata->is_irda;
+ t->irda_init = pdata->irda_init;
+ t->irda_start = pdata->irda_start;
+ t->irda_mode_switch = pdata->irda_mode_switch;
+ t->irda_shutdown = pdata->irda_shutdown;
+ t->irda_remove = pdata->irda_remove;
+ if (t->irda_init)
+ t->irda_init();
+ }
+
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!resource)) {
ret = -ENXIO;
@@ -1509,6 +1603,9 @@ static int __devexit tegra_uart_remove(struct platform_device *pdev)
if (pdev->id < 0 || pdev->id > tegra_uart_driver.nr)
pr_err("Invalid Uart instance (%d)\n", pdev->id);
+ if (t->is_irda && t->irda_remove)
+ t->irda_remove();
+
u = &t->uport;
uart_remove_one_port(&tegra_uart_driver, u);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 8fb105e03658..cd16e13f61c9 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -416,7 +416,7 @@ static void acm_read_bulk_callback(struct urb *urb)
}
usb_mark_last_busy(acm->dev);
- if (urb->status) {
+ if (urb->status && !urb->actual_length) {
dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",
__func__, urb->status);
return;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 8e051d72d6aa..e7c6ca49ab8e 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -143,7 +143,7 @@ config USB_FSL_USB2
tristate "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC || ARCH_MXC || ARCH_TEGRA
select USB_GADGET_DUALSPEED
- select USB_FSL_MPH_DR_OF if OF
+ select USB_FSL_MPH_DR_OF if OF && FSL_SOC
help
Some of Freescale PowerPC processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c8c7c687010d..13f24548cee1 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -21,6 +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
+CFLAGS_tegra_udc.o = -Werror
obj-$(CONFIG_USB_TEGRA) += tegra_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index dbc22802b43c..9f79c267890e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -45,6 +45,7 @@
#include "epautoconf.c"
#include "composite.c"
+#include "f_audio_source.c"
#include "f_mass_storage.c"
#include "u_serial.c"
#include "f_acm.c"
@@ -649,6 +650,67 @@ static struct android_usb_function accessory_function = {
.ctrlrequest = accessory_function_ctrlrequest,
};
+static int audio_source_function_init(struct android_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ struct audio_source_config *config;
+
+ config = kzalloc(sizeof(struct audio_source_config), GFP_KERNEL);
+ if (!config)
+ return -ENOMEM;
+ config->card = -1;
+ config->device = -1;
+ f->config = config;
+ return 0;
+}
+
+static void audio_source_function_cleanup(struct android_usb_function *f)
+{
+ kfree(f->config);
+}
+
+static int audio_source_function_bind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct audio_source_config *config = f->config;
+
+ return audio_source_bind_config(c, config);
+}
+
+static void audio_source_function_unbind_config(struct android_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct audio_source_config *config = f->config;
+
+ config->card = -1;
+ config->device = -1;
+}
+
+static ssize_t audio_source_pcm_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct android_usb_function *f = dev_get_drvdata(dev);
+ struct audio_source_config *config = f->config;
+
+ /* print PCM card and device numbers */
+ return sprintf(buf, "%d %d\n", config->card, config->device);
+}
+
+static DEVICE_ATTR(pcm, S_IRUGO | S_IWUSR, audio_source_pcm_show, NULL);
+
+static struct device_attribute *audio_source_function_attributes[] = {
+ &dev_attr_pcm,
+ NULL
+};
+
+static struct android_usb_function audio_source_function = {
+ .name = "audio_source",
+ .init = audio_source_function_init,
+ .cleanup = audio_source_function_cleanup,
+ .bind_config = audio_source_function_bind_config,
+ .unbind_config = audio_source_function_unbind_config,
+ .attributes = audio_source_function_attributes,
+};
static struct android_usb_function *supported_functions[] = {
&adb_function,
@@ -658,6 +720,7 @@ static struct android_usb_function *supported_functions[] = {
&rndis_function,
&mass_storage_function,
&accessory_function,
+ &audio_source_function,
NULL
};
@@ -1113,6 +1176,11 @@ static void android_disconnect(struct usb_gadget *gadget)
unsigned long flags;
composite_disconnect(gadget);
+ /* accessory HID support can be active while the
+ accessory function is not actually enabled,
+ so we need to inform it when we are disconnected.
+ */
+ acc_disconnect();
spin_lock_irqsave(&cdev->lock, flags);
dev->connected = 0;
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index ae65faaf3d77..d248ef98b532 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -33,6 +33,8 @@
#include <linux/device.h>
#include <linux/miscdevice.h>
+#include <linux/hid.h>
+#include <linux/hiddev.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/f_accessory.h>
@@ -40,7 +42,7 @@
#define BULK_BUFFER_SIZE 16384
#define ACC_STRING_SIZE 256
-#define PROTOCOL_VERSION 1
+#define PROTOCOL_VERSION 2
/* String IDs */
#define INTERFACE_STRING_INDEX 0
@@ -49,6 +51,20 @@
#define TX_REQ_MAX 4
#define RX_REQ_MAX 2
+struct acc_hid_dev {
+ struct list_head list;
+ struct hid_device *hid;
+ struct acc_dev *dev;
+ /* accessory defined ID */
+ int id;
+ /* HID report descriptor */
+ u8 *report_desc;
+ /* length of HID report descriptor */
+ int report_desc_len;
+ /* number of bytes of report_desc we have received so far */
+ int report_desc_offset;
+};
+
struct acc_dev {
struct usb_function function;
struct usb_composite_dev *cdev;
@@ -78,6 +94,8 @@ struct acc_dev {
/* set to 1 if we have a pending start request */
int start_requested;
+ int audio_mode;
+
/* synchronize access to our device file */
atomic_t open_excl;
@@ -87,7 +105,21 @@ struct acc_dev {
wait_queue_head_t write_wq;
struct usb_request *rx_req[RX_REQ_MAX];
int rx_done;
- struct delayed_work work;
+
+ /* delayed work for handling ACCESSORY_START */
+ struct delayed_work start_work;
+
+ /* worker for registering and unregistering hid devices */
+ struct work_struct hid_work;
+
+ /* list of active HID devices */
+ struct list_head hid_list;
+
+ /* list of new HID devices to register */
+ struct list_head new_hid_list;
+
+ /* list of dead HID devices to unregister */
+ struct list_head dead_hid_list;
};
static struct usb_interface_descriptor acc_interface_desc = {
@@ -296,7 +328,161 @@ static void acc_complete_set_string(struct usb_ep *ep, struct usb_request *req)
}
}
-static int __init create_bulk_endpoints(struct acc_dev *dev,
+static void acc_complete_set_hid_report_desc(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct acc_hid_dev *hid = req->context;
+ struct acc_dev *dev = hid->dev;
+ int length = req->actual;
+
+ if (req->status != 0) {
+ pr_err("acc_complete_set_hid_report_desc, err %d\n",
+ req->status);
+ return;
+ }
+
+ memcpy(hid->report_desc + hid->report_desc_offset, req->buf, length);
+ hid->report_desc_offset += length;
+ if (hid->report_desc_offset == hid->report_desc_len) {
+ /* After we have received the entire report descriptor
+ * we schedule work to initialize the HID device
+ */
+ schedule_work(&dev->hid_work);
+ }
+}
+
+static void acc_complete_send_hid_event(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct acc_hid_dev *hid = req->context;
+ int length = req->actual;
+
+ if (req->status != 0) {
+ pr_err("acc_complete_send_hid_event, err %d\n", req->status);
+ return;
+ }
+
+ hid_report_raw_event(hid->hid, HID_INPUT_REPORT, req->buf, length, 1);
+}
+
+static int acc_hid_parse(struct hid_device *hid)
+{
+ struct acc_hid_dev *hdev = hid->driver_data;
+
+ hid_parse_report(hid, hdev->report_desc, hdev->report_desc_len);
+ return 0;
+}
+
+static int acc_hid_start(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void acc_hid_stop(struct hid_device *hid)
+{
+}
+
+static int acc_hid_open(struct hid_device *hid)
+{
+ return 0;
+}
+
+static void acc_hid_close(struct hid_device *hid)
+{
+}
+
+static struct hid_ll_driver acc_hid_ll_driver = {
+ .parse = acc_hid_parse,
+ .start = acc_hid_start,
+ .stop = acc_hid_stop,
+ .open = acc_hid_open,
+ .close = acc_hid_close,
+};
+
+static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev,
+ int id, int desc_len)
+{
+ struct acc_hid_dev *hdev;
+
+ hdev = kzalloc(sizeof(*hdev), GFP_ATOMIC);
+ if (!hdev)
+ return NULL;
+ hdev->report_desc = kzalloc(desc_len, GFP_ATOMIC);
+ if (!hdev->report_desc) {
+ kfree(hdev);
+ return NULL;
+ }
+ hdev->dev = dev;
+ hdev->id = id;
+ hdev->report_desc_len = desc_len;
+
+ return hdev;
+}
+
+static struct acc_hid_dev *acc_hid_get(struct list_head *list, int id)
+{
+ struct acc_hid_dev *hid;
+
+ list_for_each_entry(hid, list, list) {
+ if (hid->id == id)
+ return hid;
+ }
+ return NULL;
+}
+
+static int acc_register_hid(struct acc_dev *dev, int id, int desc_length)
+{
+ struct acc_hid_dev *hid;
+ unsigned long flags;
+
+ /* report descriptor length must be > 0 */
+ if (desc_length <= 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ /* replace HID if one already exists with this ID */
+ hid = acc_hid_get(&dev->hid_list, id);
+ if (!hid)
+ hid = acc_hid_get(&dev->new_hid_list, id);
+ if (hid)
+ list_move(&hid->list, &dev->dead_hid_list);
+
+ hid = acc_hid_new(dev, id, desc_length);
+ if (!hid) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -ENOMEM;
+ }
+
+ list_add(&hid->list, &dev->new_hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* schedule work to register the HID device */
+ schedule_work(&dev->hid_work);
+ return 0;
+}
+
+static int acc_unregister_hid(struct acc_dev *dev, int id)
+{
+ struct acc_hid_dev *hid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->hid_list, id);
+ if (!hid)
+ hid = acc_hid_get(&dev->new_hid_list, id);
+ if (!hid) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return -EINVAL;
+ }
+
+ list_move(&hid->list, &dev->dead_hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ schedule_work(&dev->hid_work);
+ return 0;
+}
+
+static int create_bulk_endpoints(struct acc_dev *dev,
struct usb_endpoint_descriptor *in_desc,
struct usb_endpoint_descriptor *out_desc)
{
@@ -353,7 +539,7 @@ static int __init create_bulk_endpoints(struct acc_dev *dev,
return 0;
fail:
- printk(KERN_ERR "acc_bind() could not allocate requests\n");
+ pr_err("acc_bind() could not allocate requests\n");
while ((req = req_get(dev, &dev->tx_idle)))
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
@@ -510,6 +696,8 @@ static long acc_ioctl(struct file *fp, unsigned code, unsigned long value)
break;
case ACCESSORY_IS_START_REQUESTED:
return dev->start_requested;
+ case ACCESSORY_GET_AUDIO_MODE:
+ return dev->audio_mode;
}
if (!src)
return -EINVAL;
@@ -540,7 +728,7 @@ static int acc_release(struct inode *ip, struct file *fp)
return 0;
}
-/* file operations for /dev/acc_usb */
+/* file operations for /dev/usb_accessory */
static const struct file_operations acc_fops = {
.owner = THIS_MODULE,
.read = acc_read,
@@ -550,23 +738,47 @@ static const struct file_operations acc_fops = {
.release = acc_release,
};
+static int acc_hid_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret)
+ return ret;
+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
static struct miscdevice acc_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "usb_accessory",
.fops = &acc_fops,
};
+static const struct hid_device_id acc_hid_table[] = {
+ { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+
+static struct hid_driver acc_hid_driver = {
+ .name = "USB accessory",
+ .id_table = acc_hid_table,
+ .probe = acc_hid_probe,
+};
static int acc_ctrlrequest(struct usb_composite_dev *cdev,
const struct usb_ctrlrequest *ctrl)
{
struct acc_dev *dev = _acc_dev;
int value = -EOPNOTSUPP;
+ struct acc_hid_dev *hid;
+ int offset;
u8 b_requestType = ctrl->bRequestType;
u8 b_request = ctrl->bRequest;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
+ unsigned long flags;
/*
printk(KERN_INFO "acc_ctrlrequest "
@@ -579,20 +791,56 @@ static int acc_ctrlrequest(struct usb_composite_dev *cdev,
if (b_request == ACCESSORY_START) {
dev->start_requested = 1;
schedule_delayed_work(
- &dev->work, msecs_to_jiffies(10));
+ &dev->start_work, msecs_to_jiffies(10));
value = 0;
} else if (b_request == ACCESSORY_SEND_STRING) {
dev->string_index = w_index;
cdev->gadget->ep0->driver_data = dev;
cdev->req->complete = acc_complete_set_string;
value = w_length;
+ } else if (b_request == ACCESSORY_SET_AUDIO_MODE &&
+ w_index == 0 && w_length == 0) {
+ dev->audio_mode = w_value;
+ value = 0;
+ } else if (b_request == ACCESSORY_REGISTER_HID) {
+ value = acc_register_hid(dev, w_value, w_index);
+ } else if (b_request == ACCESSORY_UNREGISTER_HID) {
+ value = acc_unregister_hid(dev, w_value);
+ } else if (b_request == ACCESSORY_SET_HID_REPORT_DESC) {
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->new_hid_list, w_value);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (!hid) {
+ value = -EINVAL;
+ goto err;
+ }
+ offset = w_index;
+ if (offset != hid->report_desc_offset
+ || offset + w_length > hid->report_desc_len) {
+ value = -EINVAL;
+ goto err;
+ }
+ cdev->req->context = hid;
+ cdev->req->complete = acc_complete_set_hid_report_desc;
+ value = w_length;
+ } else if (b_request == ACCESSORY_SEND_HID_EVENT) {
+ spin_lock_irqsave(&dev->lock, flags);
+ hid = acc_hid_get(&dev->hid_list, w_value);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ if (!hid) {
+ value = -EINVAL;
+ goto err;
+ }
+ cdev->req->context = hid;
+ cdev->req->complete = acc_complete_send_hid_event;
+ value = w_length;
}
} else if (b_requestType == (USB_DIR_IN | USB_TYPE_VENDOR)) {
if (b_request == ACCESSORY_GET_PROTOCOL) {
*((u16 *)cdev->req->buf) = PROTOCOL_VERSION;
value = sizeof(u16);
- /* clear any strings left over from a previous session */
+ /* clear strings left over from a previous session */
memset(dev->manufacturer, 0, sizeof(dev->manufacturer));
memset(dev->model, 0, sizeof(dev->model));
memset(dev->description, 0, sizeof(dev->description));
@@ -600,6 +848,7 @@ static int acc_ctrlrequest(struct usb_composite_dev *cdev,
memset(dev->uri, 0, sizeof(dev->uri));
memset(dev->serial, 0, sizeof(dev->serial));
dev->start_requested = 0;
+ dev->audio_mode = 0;
}
}
@@ -612,6 +861,7 @@ static int acc_ctrlrequest(struct usb_composite_dev *cdev,
__func__);
}
+err:
if (value == -EOPNOTSUPP)
VDBG(cdev,
"unknown class-specific control req "
@@ -631,6 +881,10 @@ acc_function_bind(struct usb_configuration *c, struct usb_function *f)
DBG(cdev, "acc_function_bind dev: %p\n", dev);
+ ret = hid_register_driver(&acc_hid_driver);
+ if (ret)
+ return ret;
+
dev->start_requested = 0;
/* allocate interface ID(s) */
@@ -660,6 +914,36 @@ acc_function_bind(struct usb_configuration *c, struct usb_function *f)
}
static void
+kill_all_hid_devices(struct acc_dev *dev)
+{
+ struct acc_hid_dev *hid;
+ struct list_head *entry, *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ list_for_each_safe(entry, temp, &dev->hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ list_add(&hid->list, &dev->dead_hid_list);
+ }
+ list_for_each_safe(entry, temp, &dev->new_hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ list_add(&hid->list, &dev->dead_hid_list);
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ schedule_work(&dev->hid_work);
+}
+
+static void
+acc_hid_unbind(struct acc_dev *dev)
+{
+ hid_unregister_driver(&acc_hid_driver);
+ kill_all_hid_devices(dev);
+}
+
+static void
acc_function_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct acc_dev *dev = func_to_dev(f);
@@ -670,14 +954,104 @@ acc_function_unbind(struct usb_configuration *c, struct usb_function *f)
acc_request_free(req, dev->ep_in);
for (i = 0; i < RX_REQ_MAX; i++)
acc_request_free(dev->rx_req[i], dev->ep_out);
+
+ acc_hid_unbind(dev);
}
-static void acc_work(struct work_struct *data)
+static void acc_start_work(struct work_struct *data)
{
char *envp[2] = { "ACCESSORY=START", NULL };
kobject_uevent_env(&acc_device.this_device->kobj, KOBJ_CHANGE, envp);
}
+static int acc_hid_init(struct acc_hid_dev *hdev)
+{
+ struct hid_device *hid;
+ int ret;
+
+ hid = hid_allocate_device();
+ if (IS_ERR(hid))
+ return PTR_ERR(hid);
+
+ hid->ll_driver = &acc_hid_ll_driver;
+ hid->dev.parent = acc_device.this_device;
+
+ hid->bus = BUS_USB;
+ hid->vendor = HID_ANY_ID;
+ hid->product = HID_ANY_ID;
+ hid->driver_data = hdev;
+ ret = hid_add_device(hid);
+ if (ret) {
+ pr_err("can't add hid device: %d\n", ret);
+ hid_destroy_device(hid);
+ return ret;
+ }
+
+ hdev->hid = hid;
+ return 0;
+}
+
+static void acc_hid_delete(struct acc_hid_dev *hid)
+{
+ kfree(hid->report_desc);
+ kfree(hid);
+}
+
+static void acc_hid_work(struct work_struct *data)
+{
+ struct acc_dev *dev = _acc_dev;
+ struct list_head *entry, *temp;
+ struct acc_hid_dev *hid;
+ struct list_head new_list, dead_list;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&new_list);
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* copy hids that are ready for initialization to new_list */
+ list_for_each_safe(entry, temp, &dev->new_hid_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ if (hid->report_desc_offset == hid->report_desc_len)
+ list_move(&hid->list, &new_list);
+ }
+
+ if (list_empty(&dev->dead_hid_list)) {
+ INIT_LIST_HEAD(&dead_list);
+ } else {
+ /* move all of dev->dead_hid_list to dead_list */
+ dead_list.prev = dev->dead_hid_list.prev;
+ dead_list.next = dev->dead_hid_list.next;
+ dead_list.next->prev = &dead_list;
+ dead_list.prev->next = &dead_list;
+ INIT_LIST_HEAD(&dev->dead_hid_list);
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* register new HID devices */
+ list_for_each_safe(entry, temp, &new_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ if (acc_hid_init(hid)) {
+ pr_err("can't add HID device %p\n", hid);
+ acc_hid_delete(hid);
+ } else {
+ spin_lock_irqsave(&dev->lock, flags);
+ list_move(&hid->list, &dev->hid_list);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ }
+ }
+
+ /* remove dead HID devices */
+ list_for_each_safe(entry, temp, &dead_list) {
+ hid = list_entry(entry, struct acc_hid_dev, list);
+ list_del(&hid->list);
+ if (hid->hid)
+ hid_destroy_device(hid->hid);
+ acc_hid_delete(hid);
+ }
+}
+
static int acc_function_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
@@ -763,7 +1137,11 @@ static int acc_setup(void)
init_waitqueue_head(&dev->write_wq);
atomic_set(&dev->open_excl, 0);
INIT_LIST_HEAD(&dev->tx_idle);
- INIT_DELAYED_WORK(&dev->work, acc_work);
+ INIT_LIST_HEAD(&dev->hid_list);
+ INIT_LIST_HEAD(&dev->new_hid_list);
+ INIT_LIST_HEAD(&dev->dead_hid_list);
+ INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
+ INIT_WORK(&dev->hid_work, acc_hid_work);
/* _acc_dev must be set before calling usb_gadget_register_driver */
_acc_dev = dev;
@@ -776,10 +1154,16 @@ static int acc_setup(void)
err:
kfree(dev);
- printk(KERN_ERR "USB accessory gadget driver failed to initialize\n");
+ pr_err("USB accessory gadget driver failed to initialize\n");
return ret;
}
+static void acc_disconnect(void)
+{
+ /* unregister all HID devices if USB is disconnected */
+ kill_all_hid_devices(_acc_dev);
+}
+
static void acc_cleanup(void)
{
misc_deregister(&acc_device);
diff --git a/drivers/usb/gadget/f_audio_source.c b/drivers/usb/gadget/f_audio_source.c
new file mode 100644
index 000000000000..3ba7d7569b12
--- /dev/null
+++ b/drivers/usb/gadget/f_audio_source.c
@@ -0,0 +1,827 @@
+/*
+ * Gadget Function Driver for USB audio source device
+ *
+ * Copyright (C) 2012 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/usb/audio.h>
+#include <linux/wait.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#define SAMPLE_RATE 44100
+/* Each frame is two 16 bit integers (one per channel) */
+#define BYTES_PER_FRAME 4
+#define FRAMES_PER_MSEC (SAMPLE_RATE / 1000)
+
+#define IN_EP_MAX_PACKET_SIZE 256
+
+/* Number of requests to allocate */
+#define IN_EP_REQ_COUNT 4
+
+#define AUDIO_AC_INTERFACE 0
+#define AUDIO_AS_INTERFACE 1
+#define AUDIO_NUM_INTERFACES 2
+
+/* B.3.1 Standard AC Interface Descriptor */
+static struct usb_interface_descriptor ac_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+};
+
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
+
+#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(AUDIO_NUM_INTERFACES)
+/* 1 input terminal, 1 output terminal and 1 feature unit */
+#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH \
+ + UAC_DT_INPUT_TERMINAL_SIZE + UAC_DT_OUTPUT_TERMINAL_SIZE \
+ + UAC_DT_FEATURE_UNIT_SIZE(0))
+/* B.3.2 Class-Specific AC Interface Descriptor */
+static struct uac1_ac_header_descriptor_2 ac_header_desc = {
+ .bLength = UAC_DT_AC_HEADER_LENGTH,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_HEADER,
+ .bcdADC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
+ .bInCollection = AUDIO_NUM_INTERFACES,
+ .baInterfaceNr = {
+ [0] = AUDIO_AC_INTERFACE,
+ [1] = AUDIO_AS_INTERFACE,
+ }
+};
+
+#define INPUT_TERMINAL_ID 1
+static struct uac_input_terminal_descriptor input_terminal_desc = {
+ .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = INPUT_TERMINAL_ID,
+ .wTerminalType = UAC_INPUT_TERMINAL_MICROPHONE,
+ .bAssocTerminal = 0,
+ .wChannelConfig = 0x3,
+};
+
+DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
+
+#define FEATURE_UNIT_ID 2
+static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
+ .bLength = UAC_DT_FEATURE_UNIT_SIZE(0),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FEATURE_UNIT,
+ .bUnitID = FEATURE_UNIT_ID,
+ .bSourceID = INPUT_TERMINAL_ID,
+ .bControlSize = 2,
+};
+
+#define OUTPUT_TERMINAL_ID 3
+static struct uac1_output_terminal_descriptor output_terminal_desc = {
+ .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = OUTPUT_TERMINAL_ID,
+ .wTerminalType = UAC_TERMINAL_STREAMING,
+ .bAssocTerminal = FEATURE_UNIT_ID,
+ .bSourceID = FEATURE_UNIT_ID,
+};
+
+/* B.4.1 Standard AS Interface Descriptor */
+static struct usb_interface_descriptor as_interface_alt_0_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+static struct usb_interface_descriptor as_interface_alt_1_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+/* B.4.2 Class-Specific AS Interface Descriptor */
+static struct uac1_as_header_descriptor as_header_desc = {
+ .bLength = UAC_DT_AS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = INPUT_TERMINAL_ID,
+ .bDelay = 1,
+ .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
+};
+
+DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
+
+static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
+ .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bSubframeSize = 2,
+ .bBitResolution = 16,
+ .bSamFreqType = 1,
+};
+
+/* Standard ISO IN Endpoint Descriptor for highspeed */
+static struct usb_endpoint_descriptor hs_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+ .bInterval = 4, /* poll 1 per millisecond */
+};
+
+/* Standard ISO IN Endpoint Descriptor for highspeed */
+static struct usb_endpoint_descriptor fs_as_in_ep_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_SYNC_SYNC
+ | USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = __constant_cpu_to_le16(IN_EP_MAX_PACKET_SIZE),
+ .bInterval = 1, /* poll 1 per millisecond */
+};
+
+/* Class-specific AS ISO OUT Endpoint Descriptor */
+static struct uac_iso_endpoint_descriptor as_iso_in_desc = {
+ .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 1,
+ .bLockDelayUnits = 1,
+ .wLockDelay = __constant_cpu_to_le16(1),
+};
+
+static struct usb_descriptor_header *hs_audio_desc[] = {
+ (struct usb_descriptor_header *)&ac_interface_desc,
+ (struct usb_descriptor_header *)&ac_header_desc,
+
+ (struct usb_descriptor_header *)&input_terminal_desc,
+ (struct usb_descriptor_header *)&output_terminal_desc,
+ (struct usb_descriptor_header *)&feature_unit_desc,
+
+ (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_header_desc,
+
+ (struct usb_descriptor_header *)&as_type_i_desc,
+
+ (struct usb_descriptor_header *)&hs_as_in_ep_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *fs_audio_desc[] = {
+ (struct usb_descriptor_header *)&ac_interface_desc,
+ (struct usb_descriptor_header *)&ac_header_desc,
+
+ (struct usb_descriptor_header *)&input_terminal_desc,
+ (struct usb_descriptor_header *)&output_terminal_desc,
+ (struct usb_descriptor_header *)&feature_unit_desc,
+
+ (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+ (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+ (struct usb_descriptor_header *)&as_header_desc,
+
+ (struct usb_descriptor_header *)&as_type_i_desc,
+
+ (struct usb_descriptor_header *)&fs_as_in_ep_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct snd_pcm_hardware audio_hw_info = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER,
+
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 2,
+ .channels_max = 2,
+ .rate_min = SAMPLE_RATE,
+ .rate_max = SAMPLE_RATE,
+
+ .buffer_bytes_max = 1024 * 1024,
+ .period_bytes_min = 64,
+ .period_bytes_max = 512 * 1024,
+ .periods_min = 2,
+ .periods_max = 1024,
+};
+
+/*-------------------------------------------------------------------------*/
+
+struct audio_source_config {
+ int card;
+ int device;
+};
+
+struct audio_dev {
+ struct usb_function func;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+
+ struct list_head idle_reqs;
+ struct usb_ep *in_ep;
+ struct usb_endpoint_descriptor *in_desc;
+
+ spinlock_t lock;
+
+ /* beginning, end and current position in our buffer */
+ void *buffer_start;
+ void *buffer_end;
+ void *buffer_pos;
+
+ /* byte size of a "period" */
+ unsigned int period;
+ /* bytes sent since last call to snd_pcm_period_elapsed */
+ unsigned int period_offset;
+ /* time we started playing */
+ ktime_t start_time;
+ /* number of frames sent since start_time */
+ s64 frames_sent;
+};
+
+static inline struct audio_dev *func_to_audio(struct usb_function *f)
+{
+ return container_of(f, struct audio_dev, func);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *audio_request_new(struct usb_ep *ep, int buffer_size)
+{
+ struct usb_request *req = usb_ep_alloc_request(ep, GFP_KERNEL);
+ if (!req)
+ return NULL;
+
+ req->buf = kmalloc(buffer_size, GFP_KERNEL);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ return NULL;
+ }
+ req->length = buffer_size;
+ return req;
+}
+
+static void audio_request_free(struct usb_request *req, struct usb_ep *ep)
+{
+ if (req) {
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+ }
+}
+
+static void audio_req_put(struct audio_dev *audio, struct usb_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ list_add_tail(&req->list, &audio->idle_reqs);
+ spin_unlock_irqrestore(&audio->lock, flags);
+}
+
+static struct usb_request *audio_req_get(struct audio_dev *audio)
+{
+ unsigned long flags;
+ struct usb_request *req;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ if (list_empty(&audio->idle_reqs)) {
+ req = 0;
+ } else {
+ req = list_first_entry(&audio->idle_reqs, struct usb_request,
+ list);
+ list_del(&req->list);
+ }
+ spin_unlock_irqrestore(&audio->lock, flags);
+ return req;
+}
+
+/* send the appropriate number of packets to match our bitrate */
+static void audio_send(struct audio_dev *audio)
+{
+ struct snd_pcm_runtime *runtime;
+ struct usb_request *req;
+ int length, length1, length2, ret;
+ s64 msecs;
+ s64 frames;
+ ktime_t now;
+
+ /* audio->substream will be null if we have been closed */
+ if (!audio->substream)
+ return;
+ /* audio->buffer_pos will be null if we have been stopped */
+ if (!audio->buffer_pos)
+ return;
+
+ runtime = audio->substream->runtime;
+
+ /* compute number of frames to send */
+ now = ktime_get();
+ msecs = ktime_to_ns(now) - ktime_to_ns(audio->start_time);
+ do_div(msecs, 1000000);
+ frames = msecs * SAMPLE_RATE;
+ do_div(frames, 1000);
+
+ /* Readjust our frames_sent if we fall too far behind.
+ * If we get too far behind it is better to drop some frames than
+ * to keep sending data too fast in an attempt to catch up.
+ */
+ if (frames - audio->frames_sent > 10 * FRAMES_PER_MSEC)
+ audio->frames_sent = frames - FRAMES_PER_MSEC;
+
+ frames -= audio->frames_sent;
+
+ /* We need to send something to keep the pipeline going */
+ if (frames <= 0)
+ frames = FRAMES_PER_MSEC;
+
+ while (frames > 0) {
+ req = audio_req_get(audio);
+ if (!req)
+ break;
+
+ length = frames_to_bytes(runtime, frames);
+ if (length > IN_EP_MAX_PACKET_SIZE)
+ length = IN_EP_MAX_PACKET_SIZE;
+
+ if (audio->buffer_pos + length > audio->buffer_end)
+ length1 = audio->buffer_end - audio->buffer_pos;
+ else
+ length1 = length;
+ memcpy(req->buf, audio->buffer_pos, length1);
+ if (length1 < length) {
+ /* Wrap around and copy remaining length
+ * at beginning of buffer.
+ */
+ length2 = length - length1;
+ memcpy(req->buf + length1, audio->buffer_start,
+ length2);
+ audio->buffer_pos = audio->buffer_start + length2;
+ } else {
+ audio->buffer_pos += length1;
+ if (audio->buffer_pos >= audio->buffer_end)
+ audio->buffer_pos = audio->buffer_start;
+ }
+
+ req->length = length;
+ ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
+ if (ret < 0) {
+ pr_err("usb_ep_queue failed ret: %d\n", ret);
+ audio_req_put(audio, req);
+ break;
+ }
+
+ frames -= bytes_to_frames(runtime, length);
+ audio->frames_sent += bytes_to_frames(runtime, length);
+ }
+}
+
+static void audio_control_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ /* nothing to do here */
+}
+
+static void audio_data_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct audio_dev *audio = req->context;
+
+ pr_debug("audio_data_complete req->status %d req->actual %d\n",
+ req->status, req->actual);
+
+ audio_req_put(audio, req);
+
+ if (!audio->buffer_start)
+ return;
+
+ audio->period_offset += req->actual;
+ if (audio->period_offset >= audio->period) {
+ snd_pcm_period_elapsed(audio->substream);
+ audio->period_offset = 0;
+ }
+ audio_send(audio);
+}
+
+static int audio_set_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ int value = -EOPNOTSUPP;
+ u16 ep = le16_to_cpu(ctrl->wIndex);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ switch (ctrl->bRequest) {
+ case UAC_SET_CUR:
+ case UAC_SET_MIN:
+ case UAC_SET_MAX:
+ case UAC_SET_RES:
+ value = len;
+ break;
+ default:
+ break;
+ }
+
+ return value;
+}
+
+static int audio_get_endpoint_req(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ int value = -EOPNOTSUPP;
+ u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+ u16 len = le16_to_cpu(ctrl->wLength);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u8 *buf = cdev->req->buf;
+
+ pr_debug("bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+ ctrl->bRequest, w_value, len, ep);
+
+ if (w_value == UAC_EP_CS_ATTR_SAMPLE_RATE << 8) {
+ switch (ctrl->bRequest) {
+ case UAC_GET_CUR:
+ case UAC_GET_MIN:
+ case UAC_GET_MAX:
+ case UAC_GET_RES:
+ /* return our sample rate */
+ buf[0] = (u8)SAMPLE_RATE;
+ buf[1] = (u8)(SAMPLE_RATE >> 8);
+ buf[2] = (u8)(SAMPLE_RATE >> 16);
+ value = 3;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return value;
+}
+
+static int
+audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* composite driver infrastructure handles everything; interface
+ * activation uses set_alt().
+ */
+ switch (ctrl->bRequestType) {
+ case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_set_endpoint_req(f, ctrl);
+ break;
+
+ case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
+ value = audio_get_endpoint_req(f, ctrl);
+ break;
+ }
+
+ /* respond with data transfer or status phase? */
+ if (value >= 0) {
+ pr_debug("audio req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->zero = 0;
+ req->length = value;
+ req->complete = audio_control_complete;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0)
+ pr_err("audio response on err %d\n", value);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static int audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+ struct audio_dev *audio = func_to_audio(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+
+ pr_debug("audio_set_alt intf %d, alt %d\n", intf, alt);
+ config_ep_by_speed(cdev->gadget, f, audio->in_ep);
+ usb_ep_enable(audio->in_ep);
+ return 0;
+}
+
+static void audio_disable(struct usb_function *f)
+{
+ struct audio_dev *audio = func_to_audio(f);
+
+ pr_debug("audio_disable\n");
+ usb_ep_disable(audio->in_ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void audio_build_desc(struct audio_dev *audio)
+{
+ u8 *sam_freq;
+ int rate;
+
+ /* Set channel numbers */
+ input_terminal_desc.bNrChannels = 2;
+ as_type_i_desc.bNrChannels = 2;
+
+ /* Set sample rates */
+ rate = SAMPLE_RATE;
+ sam_freq = as_type_i_desc.tSamFreq[0];
+ memcpy(sam_freq, &rate, 3);
+}
+
+/* audio function driver setup/binding */
+static int
+audio_bind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = c->cdev;
+ struct audio_dev *audio = func_to_audio(f);
+ int status;
+ struct usb_ep *ep;
+ struct usb_request *req;
+ int i;
+
+ audio_build_desc(audio);
+
+ /* allocate instance-specific interface IDs, and patch descriptors */
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ ac_interface_desc.bInterfaceNumber = status;
+
+ status = usb_interface_id(c, f);
+ if (status < 0)
+ goto fail;
+ as_interface_alt_0_desc.bInterfaceNumber = status;
+ as_interface_alt_1_desc.bInterfaceNumber = status;
+
+ status = -ENODEV;
+
+ /* allocate our endpoint */
+ ep = usb_ep_autoconfig(cdev->gadget, &fs_as_in_ep_desc);
+ if (!ep)
+ goto fail;
+ audio->in_ep = ep;
+ ep->driver_data = audio; /* claim */
+
+ if (gadget_is_dualspeed(c->cdev->gadget))
+ hs_as_in_ep_desc.bEndpointAddress =
+ fs_as_in_ep_desc.bEndpointAddress;
+
+ f->descriptors = fs_audio_desc;
+ f->hs_descriptors = hs_audio_desc;
+
+ for (i = 0, status = 0; i < IN_EP_REQ_COUNT && status == 0; i++) {
+ req = audio_request_new(ep, IN_EP_MAX_PACKET_SIZE);
+ if (req) {
+ req->context = audio;
+ req->complete = audio_data_complete;
+ audio_req_put(audio, req);
+ } else
+ status = -ENOMEM;
+ }
+
+fail:
+ return status;
+}
+
+static void
+audio_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+ struct audio_dev *audio = func_to_audio(f);
+ struct usb_request *req;
+
+ while ((req = audio_req_get(audio)))
+ audio_request_free(req, audio->in_ep);
+
+ snd_card_free_when_closed(audio->card);
+ kfree(audio);
+}
+
+static void audio_pcm_playback_start(struct audio_dev *audio)
+{
+ audio->start_time = ktime_get();
+ audio->frames_sent = 0;
+ audio_send(audio);
+}
+
+static void audio_pcm_playback_stop(struct audio_dev *audio)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ audio->buffer_start = 0;
+ audio->buffer_end = 0;
+ audio->buffer_pos = 0;
+ spin_unlock_irqrestore(&audio->lock, flags);
+}
+
+static int audio_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = substream->private_data;
+
+ runtime->private_data = audio;
+ runtime->hw = audio_hw_info;
+ snd_pcm_limit_hw_rates(runtime);
+ runtime->hw.channels_max = 2;
+
+ audio->substream = substream;
+ return 0;
+}
+
+static int audio_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct audio_dev *audio = substream->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&audio->lock, flags);
+ audio->substream = NULL;
+ spin_unlock_irqrestore(&audio->lock, flags);
+
+ return 0;
+}
+
+static int audio_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
+
+ if (rate != SAMPLE_RATE)
+ return -EINVAL;
+ if (channels != 2)
+ return -EINVAL;
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(params));
+}
+
+static int audio_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int audio_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = runtime->private_data;
+
+ audio->period = snd_pcm_lib_period_bytes(substream);
+ audio->period_offset = 0;
+ audio->buffer_start = runtime->dma_area;
+ audio->buffer_end = audio->buffer_start
+ + snd_pcm_lib_buffer_bytes(substream);
+ audio->buffer_pos = audio->buffer_start;
+
+ return 0;
+}
+
+static snd_pcm_uframes_t audio_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct audio_dev *audio = runtime->private_data;
+ ssize_t bytes = audio->buffer_pos - audio->buffer_start;
+
+ /* return offset of next frame to fill in our buffer */
+ return bytes_to_frames(runtime, bytes);
+}
+
+static int audio_pcm_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct audio_dev *audio = substream->runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ audio_pcm_playback_start(audio);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ audio_pcm_playback_stop(audio);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct snd_pcm_ops audio_playback_ops = {
+ .open = audio_pcm_open,
+ .close = audio_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = audio_pcm_hw_params,
+ .hw_free = audio_pcm_hw_free,
+ .prepare = audio_pcm_prepare,
+ .trigger = audio_pcm_playback_trigger,
+ .pointer = audio_pcm_pointer,
+};
+
+int audio_source_bind_config(struct usb_configuration *c,
+ struct audio_source_config *config)
+{
+ struct audio_dev *audio;
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ int err;
+
+ config->card = -1;
+ config->device = -1;
+
+ audio = kzalloc(sizeof *audio, GFP_KERNEL);
+ if (!audio)
+ return -ENOMEM;
+
+ audio->func.name = "audio_source";
+
+ spin_lock_init(&audio->lock);
+
+ audio->func.bind = audio_bind;
+ audio->func.unbind = audio_unbind;
+ audio->func.set_alt = audio_set_alt;
+ audio->func.setup = audio_setup;
+ audio->func.disable = audio_disable;
+ audio->in_desc = &fs_as_in_ep_desc;
+
+ INIT_LIST_HEAD(&audio->idle_reqs);
+
+ err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+ THIS_MODULE, 0, &card);
+ if (err)
+ goto snd_card_fail;
+
+ snd_card_set_dev(card, &c->cdev->gadget->dev);
+
+ err = snd_pcm_new(card, "USB audio source", 0, 1, 0, &pcm);
+ if (err)
+ goto pcm_fail;
+ pcm->private_data = audio;
+ pcm->info_flags = 0;
+ audio->pcm = pcm;
+
+ strlcpy(pcm->name, "USB gadget audio", sizeof(pcm->name));
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &audio_playback_ops);
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ NULL, 0, 64 * 1024);
+
+ strlcpy(card->driver, "audio_source", sizeof(card->driver));
+ strlcpy(card->shortname, card->driver, sizeof(card->shortname));
+ strlcpy(card->longname, "USB accessory audio source",
+ sizeof(card->longname));
+
+ err = snd_card_register(card);
+ if (err)
+ goto register_fail;
+
+ err = usb_add_function(c, &audio->func);
+ if (err)
+ goto add_fail;
+
+ config->card = pcm->card->number;
+ config->device = pcm->device;
+ audio->card = card;
+ return 0;
+
+add_fail:
+register_fail:
+pcm_fail:
+ snd_card_free(audio->card);
+snd_card_fail:
+ kfree(audio);
+ return err;
+}
diff --git a/drivers/usb/gadget/tegra_udc.c b/drivers/usb/gadget/tegra_udc.c
index aad99a6cd66e..ddf9c602dc89 100644
--- a/drivers/usb/gadget/tegra_udc.c
+++ b/drivers/usb/gadget/tegra_udc.c
@@ -129,8 +129,9 @@ 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;
+ struct ep_td_struct *curr_td, *next_td = 0;
int j;
+ int count;
BUG_ON(!(in_irq() || irqs_disabled()));
udc = (struct tegra_udc *)ep->udc;
/* Removed the req from tegra_ep->queue */
@@ -143,12 +144,19 @@ static void done(struct tegra_ep *ep, struct tegra_req *req, int status)
status = req->req.status;
/* Free dtd for the request */
- next_td = req->head;
- for (j = 0; j < req->dtd_count; j++) {
+ count = 0;
+ if (ep->last_td) {
+ next_td = ep->last_td;
+ count = ep->last_dtd_count;
+ }
+ ep->last_td = req->head;
+ ep->last_dtd_count = req->dtd_count;
+
+ for (j = 0; j < count; j++) {
curr_td = next_td;
- if (j != req->dtd_count - 1)
+ if (j != count - 1) {
next_td = curr_td->next_td_virt;
-
+ }
dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
}
@@ -568,6 +576,8 @@ static int tegra_ep_enable(struct usb_ep *_ep,
ep->ep.maxpacket = max;
ep->desc = desc;
ep->stopped = 0;
+ ep->last_td = 0;
+ ep->last_dtd_count = 0;
/* Controller related setup
* Init EPx Queue Head (Ep Capabilites field in QH
@@ -610,6 +620,8 @@ static int tegra_ep_disable(struct usb_ep *_ep)
unsigned long flags = 0;
u32 epctrl;
int ep_num;
+ struct ep_td_struct *curr_td, *next_td;
+ int j;
ep = container_of(_ep, struct tegra_ep, ep);
if (!_ep || !ep->desc) {
@@ -638,6 +650,18 @@ static int tegra_ep_disable(struct usb_ep *_ep)
ep->desc = NULL;
ep->stopped = 1;
+ if (ep->last_td) {
+ next_td = ep->last_td;
+ for (j = 0; j < ep->last_dtd_count; j++) {
+ curr_td = next_td;
+ dma_pool_free(udc->td_pool, curr_td, curr_td->td_dma);
+ if (j != ep->last_dtd_count - 1) {
+ next_td = curr_td->next_td_virt;
+ }
+ }
+ }
+ ep->last_td =0;
+ ep->last_dtd_count = 0;
spin_unlock_irqrestore(&udc->lock, flags);
VDBG("disabled %s OK", _ep->name);
@@ -1216,6 +1240,76 @@ static int tegra_set_selfpowered(struct usb_gadget *gadget, int is_on)
return 0;
}
+static int tegra_usb_set_charging_current(struct tegra_udc *udc)
+{
+ int max_ua;
+
+ if (NULL == udc->vbus_reg)
+ return 0;
+
+ switch (udc->connect_type) {
+ case CONNECT_TYPE_NONE:
+ pr_debug("detected USB charging is disabled");
+ max_ua = 0;
+ break;
+ case CONNECT_TYPE_SDP:
+ pr_debug("detected SDP port");
+ max_ua = USB_CHARGING_SDP_CURRENT_LIMIT_UA;
+ break;
+ case CONNECT_TYPE_DCP:
+ pr_debug("detected DCP port(wall charger)");
+ max_ua = USB_CHARGING_DCP_CURRENT_LIMIT_UA;
+ break;
+ case CONNECT_TYPE_CDP:
+ pr_debug("detected CDP port(1A USB port)");
+ max_ua = USB_CHARGING_CDP_CURRENT_LIMIT_UA;
+ break;
+ case CONNECT_TYPE_NON_STANDARD_CHARGER:
+ pr_debug("detected non-standard charging port");
+ max_ua = USB_CHARGING_NON_STANDARD_CHARGER_CURRENT_LIMIT_UA;
+ break;
+ default:
+ pr_debug("detected USB charging type is unknown");
+ max_ua = 0;
+ }
+
+ return regulator_set_current_limit(udc->vbus_reg, 0, max_ua);
+}
+
+static void tegra_detect_charging_type_is_cdp_or_dcp(struct tegra_udc *udc)
+{
+ u32 portsc;
+ u32 temp;
+ unsigned long flags;
+
+ /* use spinlock to prevent kernel preemption here */
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* set controller to run which cause D+ pull high */
+ temp = udc_readl(udc, USB_CMD_REG_OFFSET);
+ temp |= USB_CMD_RUN_STOP;
+ udc_writel(udc, temp, USB_CMD_REG_OFFSET);
+
+ udelay(10);
+
+ /* use D+ and D- status to check it is CDP or DCP */
+ portsc = udc_readl(udc, PORTSCX_REG_OFFSET) & PORTSCX_LINE_STATUS_BITS;
+ if (portsc == (PORTSCX_LINE_STATUS_DP_BIT | PORTSCX_LINE_STATUS_DM_BIT))
+ udc->connect_type = CONNECT_TYPE_DCP;
+ else if (portsc == PORTSCX_LINE_STATUS_DP_BIT)
+ udc->connect_type = CONNECT_TYPE_CDP;
+ else
+ /*
+ * If it take more 100mS between D+ pull high and read Line
+ * Status, host might initiate the RESET, then we see both
+ * line status as 0 (SE0). This really should not happen as we
+ * disabled the kernel preemption before reaching here.
+ */
+ BUG();
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
/**
* Notify controller that VBUS is powered, called by whatever
* detects VBUS sessions
@@ -1238,13 +1332,10 @@ static int tegra_vbus_session(struct usb_gadget *gadget, int is_active)
dr_controller_reset(udc);
udc->vbus_active = 0;
udc->usb_state = USB_STATE_DEFAULT;
+ udc->connect_type = CONNECT_TYPE_NONE;
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);
- }
+ tegra_usb_set_charging_current(udc);
} else if (!udc->vbus_active && is_active) {
tegra_usb_phy_power_on(udc->phy);
/* setup the controller in the device mode */
@@ -1256,18 +1347,23 @@ static int tegra_vbus_session(struct usb_gadget *gadget, int is_active)
udc->ep0_state = WAIT_FOR_SETUP;
udc->ep0_dir = 0;
udc->vbus_active = 1;
+ if (tegra_usb_phy_charger_detected(udc->phy)) {
+ tegra_detect_charging_type_is_cdp_or_dcp(udc);
+ } else {
+ udc->connect_type = CONNECT_TYPE_SDP;
+ /*
+ * Schedule work to wait for 1000 msec and check for
+ * a non-standard charger if setup packet is not
+ * received.
+ */
+ schedule_delayed_work(&udc->work, msecs_to_jiffies(
+ USB_CHARGER_DETECTION_WAIT_TIME_MS));
+ }
/* 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);
+ tegra_usb_set_charging_current(udc);
}
+
return 0;
}
@@ -2095,26 +2191,18 @@ static void tegra_udc_irq_work(struct work_struct *irq_work)
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.
+/*
+ * When VBUS is detected we already know it is DCP/SDP/CDP devices if it is a
+ * standard device; If we did not receive EP0 setup packet, we can assuming it
+ * is a charger capable of 1.8A charging.
*/
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);
- }
- }
+ udc->connect_type = CONNECT_TYPE_NON_STANDARD_CHARGER;
+ tegra_usb_set_charging_current(udc);
DBG("%s(%d) END\n", __func__, __LINE__);
}
@@ -2159,10 +2247,8 @@ static irqreturn_t tegra_udc_irq(int irq, void *_udc)
}
/* Disable ISR for OTG host mode */
- if (udc->stopped) {
- spin_unlock_irqrestore(&udc->lock, flags);
- return status;
- }
+ if (udc->stopped)
+ goto done;
/* Fence read for coherency of AHB master intiated writes */
readb(IO_ADDRESS(IO_PPCS_PHYS + USB1_PREFETCH_ID));
@@ -2170,6 +2256,9 @@ static irqreturn_t tegra_udc_irq(int irq, void *_udc)
irq_src = udc_readl(udc, USB_STS_REG_OFFSET) &
udc_readl(udc, USB_INTR_REG_OFFSET);
+ if (irq_src == 0)
+ goto done;
+
/* Clear notification bits */
udc_writel(udc, irq_src, USB_STS_REG_OFFSET);
@@ -2226,6 +2315,7 @@ static irqreturn_t tegra_udc_irq(int irq, void *_udc)
if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR))
VDBG("Error IRQ %x", irq_src);
+done:
spin_unlock_irqrestore(&udc->lock, flags);
return status;
}
@@ -2274,11 +2364,13 @@ static int tegra_udc_start(struct usb_gadget_driver *driver,
/* 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);
+ if (vbus_enabled(udc)) {
+ 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);
@@ -2632,7 +2724,7 @@ static int __init tegra_udc_probe(struct platform_device *pdev)
}
#else
/* Power down the phy if cable is not connected */
- if (!vbus_enabled())
+ if (!vbus_enabled(udc))
tegra_usb_phy_power_off(udc->phy);
#endif
diff --git a/drivers/usb/gadget/tegra_udc.h b/drivers/usb/gadget/tegra_udc.h
index e94543fd98e3..094e3eb0e458 100644
--- a/drivers/usb/gadget/tegra_udc.h
+++ b/drivers/usb/gadget/tegra_udc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* Description:
* High-speed USB device controller driver.
@@ -38,7 +38,11 @@
#define USB_MAX_CTRL_PAYLOAD 64
/* Charger current limit=1800mA, as per the USB charger spec */
-#define USB_CHARGING_CURRENT_LIMIT_MA 1800
+#define USB_CHARGING_DCP_CURRENT_LIMIT_UA 1800000
+#define USB_CHARGING_CDP_CURRENT_LIMIT_UA 900000
+#define USB_CHARGING_SDP_CURRENT_LIMIT_UA 100000
+#define USB_CHARGING_NON_STANDARD_CHARGER_CURRENT_LIMIT_UA 1800000
+
/* 1 sec wait time for charger detection after vbus is detected */
#define USB_CHARGER_DETECTION_WAIT_TIME_MS 1000
#define BOOST_TRIGGER_SIZE 4096
@@ -156,6 +160,8 @@
#define PORTSCX_PORT_SUSPEND 0x00000080
#define PORTSCX_PORT_RESET 0x00000100
#define PORTSCX_LINE_STATUS_BITS 0x00000C00
+#define PORTSCX_LINE_STATUS_DP_BIT 0x00000800
+#define PORTSCX_LINE_STATUS_DM_BIT 0x00000400
#define PORTSCX_PORT_POWER 0x00001000
#define PORTSCX_PORT_INDICTOR_CTRL 0x0000C000
#define PORTSCX_PORT_TEST_CTRL 0x000F0000
@@ -390,11 +396,21 @@ struct tegra_ep {
struct ep_queue_head *qh;
const struct usb_endpoint_descriptor *desc;
struct usb_gadget *gadget;
+ struct ep_td_struct *last_td;
+ int last_dtd_count;
char name[14];
unsigned stopped:1;
};
+enum tegra_connect_type {
+ CONNECT_TYPE_NONE,
+ CONNECT_TYPE_SDP,
+ CONNECT_TYPE_DCP,
+ CONNECT_TYPE_CDP,
+ CONNECT_TYPE_NON_STANDARD_CHARGER
+};
+
struct tegra_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
@@ -415,6 +431,7 @@ struct tegra_udc {
struct work_struct boost_cpufreq_work;
/* irq work for controlling the usb power */
struct work_struct irq_work;
+ enum tegra_connect_type connect_type;
void __iomem *regs;
size_t ep_qh_size; /* size after alignment adjustment*/
dma_addr_t ep_qh_dma; /* dma address of QH */
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 5c25783a7643..0eb20989d67e 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -334,6 +334,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_COMPLETING;
stopped = (state == QH_STATE_IDLE);
+ ehci_sync_qh(ehci, qh);
rescan:
last = NULL;
last_status = -EINPROGRESS;
@@ -367,6 +368,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (qtd == end)
break;
+ ehci_sync_qtd(ehci, qtd);
/* hardware copies qtd out of qh overlay */
rmb ();
token = hc32_to_cpu(ehci, qtd->hw_token);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 33504e402611..af6fa87fb645 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -156,7 +156,6 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
irqreturn_t irq_status;
- bool pmc_remote_wakeup = false;
spin_lock(&ehci->lock);
irq_status = tegra_usb_phy_irq(tegra->phy);
@@ -166,8 +165,9 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
}
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);
+ return irq_status;
}
spin_unlock(&ehci->lock);
@@ -178,10 +178,6 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
irq_status = ehci_irq(hcd);
- if (pmc_remote_wakeup) {
- ehci->controller_remote_wakeup = false;
- }
-
if (ehci->controller_remote_wakeup) {
ehci->controller_remote_wakeup = false;
tegra_usb_phy_pre_resume(tegra->phy, true);
@@ -202,7 +198,6 @@ static int tegra_ehci_hub_control(
{
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;
u32 __iomem *status_reg;
@@ -216,6 +211,7 @@ static int tegra_ehci_hub_control(
switch (typeReq) {
case GetPortStatus:
if (tegra->port_resuming) {
+ u32 cmd;
int delay = ehci->reset_done[wIndex-1] - jiffies;
/* Sometimes it seems we get called too soon... In that case, wait.*/
if (delay > 0) {
@@ -230,9 +226,11 @@ static int tegra_ehci_hub_control(
tegra_usb_phy_post_resume(tegra->phy);
tegra->port_resuming = 0;
/* If run bit is not set by now enable it */
- if (ehci->command & CMD_RUN) {
+ cmd = ehci_readl(ehci, &ehci->regs->command);
+ if (!(cmd & CMD_RUN)) {
+ cmd |= CMD_RUN;
ehci->command |= CMD_RUN;
- ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, cmd, &ehci->regs->command);
}
/* Now we can safely re-enable irqs */
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
@@ -553,10 +551,10 @@ static int tegra_ehci_remove(struct platform_device *pdev)
tegra_usb_phy_power_on(tegra->phy);
usb_remove_hcd(hcd);
- usb_put_hcd(hcd);
tegra_usb_phy_power_off(tegra->phy);
tegra_usb_phy_close(tegra->phy);
iounmap(hcd->regs);
+ usb_put_hcd(hcd);
return 0;
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index cfbdf32ec0b2..569cdf5a4c03 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -767,10 +767,32 @@ static inline void ehci_sync_mem(void)
{
mb();
}
+
+/*
+ * DMA coherent memory on ARM which features speculative prefetcher doesn't
+ * guarantee coherency, so introduce the helpers which can invalidate QH and
+ * QTD in L1/L2 cache. It enforces CPU reads from memory directly.
+ */
+static inline void ehci_sync_qh(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+ dma_sync_single_for_cpu(ehci_to_hcd(ehci)->self.controller, qh->qh_dma,
+ sizeof(struct ehci_qh_hw), DMA_FROM_DEVICE);
+}
+static inline void ehci_sync_qtd(struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+ dma_sync_single_for_cpu(ehci_to_hcd(ehci)->self.controller,
+ qtd->qtd_dma, sizeof(struct ehci_qtd), DMA_FROM_DEVICE);
+}
#else
static inline void ehci_sync_mem()
{
}
+static inline void ehci_sync_qh(struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+}
+static inline void ehci_sync_qtd(struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+}
#endif
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index c09f9b829382..cbedff4e254f 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg_id.o
# transceiver drivers
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
obj-$(CONFIG_USB_COLIBRI_OTG) += colibri-otg.o
+CFLAGS_tegra-otg.o = -Werror
obj-$(CONFIG_USB_TEGRA_OTG) += tegra-otg.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c
index a5e85bf90d14..22e303ede24e 100644
--- a/drivers/usb/otg/tegra-otg.c
+++ b/drivers/usb/otg/tegra-otg.c
@@ -53,6 +53,7 @@ struct tegra_otg_data {
struct otg_transceiver otg;
unsigned long int_status;
spinlock_t lock;
+ struct mutex irq_work_mutex;
void __iomem *regs;
struct clk *clk;
int irq;
@@ -62,7 +63,7 @@ struct tegra_otg_data {
bool clk_enabled;
bool interrupt_mode;
bool builtin_host;
- bool suspended
+ bool suspended;
};
static struct tegra_otg_data *tegra_clone;
@@ -105,7 +106,7 @@ static unsigned long enable_interrupt(struct tegra_otg_data *tegra, bool en)
if (tegra->builtin_host)
val |= USB_INT_EN;
else
- val = USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN;
+ val |= USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN | USB_ID_PIN_WAKEUP_EN;
}
else
val &= ~USB_INT_EN;
@@ -181,6 +182,12 @@ static void tegra_stop_host(struct tegra_otg_data *tegra)
DBG("%s(%d) End\n", __func__, __LINE__);
}
+static void tegra_otg_notify_event(struct otg_transceiver *otg,
+ enum usb_xceiv_events event)
+{
+ otg->last_event = event;
+ atomic_notifier_call_chain(&otg->notifier, event, NULL);
+}
static void tegra_change_otg_state(struct tegra_otg_data *tegra,
enum usb_otg_state to)
@@ -202,16 +209,24 @@ static void tegra_change_otg_state(struct tegra_otg_data *tegra,
tegra_state_name(to));
if (from == OTG_STATE_A_SUSPEND) {
- if (to == OTG_STATE_B_PERIPHERAL && otg->gadget)
+ if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) {
usb_gadget_vbus_connect(otg->gadget);
- else if (to == OTG_STATE_A_HOST)
+ tegra_otg_notify_event(otg, USB_EVENT_VBUS);
+ }
+ else if (to == OTG_STATE_A_HOST) {
tegra_start_host(tegra);
+ tegra_otg_notify_event(otg, USB_EVENT_ID);
+ }
} else if (from == OTG_STATE_A_HOST) {
- if (to == OTG_STATE_A_SUSPEND)
+ if (to == OTG_STATE_A_SUSPEND) {
tegra_stop_host(tegra);
+ tegra_otg_notify_event(otg, USB_EVENT_NONE);
+ }
} else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) {
- if (to == OTG_STATE_A_SUSPEND)
+ if (to == OTG_STATE_A_SUSPEND) {
usb_gadget_vbus_disconnect(otg->gadget);
+ tegra_otg_notify_event(otg, USB_EVENT_NONE);
+ }
}
}
}
@@ -221,16 +236,19 @@ static void irq_work(struct work_struct *work)
struct tegra_otg_data *tegra =
container_of(work, struct tegra_otg_data, work);
struct otg_transceiver *otg = &tegra->otg;
- enum usb_otg_state from = otg->state;
+ enum usb_otg_state from;
enum usb_otg_state to = OTG_STATE_UNDEFINED;
unsigned long flags;
unsigned long status;
+ mutex_lock(&tegra->irq_work_mutex);
+
spin_lock_irqsave(&tegra->lock, flags);
+ from = otg->state;
status = tegra->int_status;
/* Debug prints */
- DBG("%s(%d) status = 0x%x\n", __func__, __LINE__, status);
+ DBG("%s(%d) status = 0x%lx\n", __func__, __LINE__, status);
if ((status & USB_ID_INT_STATUS) &&
(status & USB_VBUS_INT_STATUS))
DBG("%s(%d) got vbus & id interrupt\n", __func__, __LINE__);
@@ -250,6 +268,7 @@ static void irq_work(struct work_struct *work)
spin_unlock_irqrestore(&tegra->lock, flags);
tegra_change_otg_state(tegra, to);
+ mutex_unlock(&tegra->irq_work_mutex);
}
static irqreturn_t tegra_otg_irq(int irq, void *data)
@@ -260,10 +279,10 @@ static irqreturn_t tegra_otg_irq(int irq, void *data)
spin_lock_irqsave(&tegra->lock, flags);
val = otg_readl(tegra, USB_PHY_WAKEUP);
- DBG("%s(%d) interrupt val = 0x%x\n", __func__, __LINE__, val);
+ DBG("%s(%d) interrupt val = 0x%lx\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);
+ DBG("%s(%d) PHY_WAKEUP = 0x%lx\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;
@@ -355,7 +374,7 @@ 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;
+ unsigned int host;
if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
return -EINVAL;
@@ -395,6 +414,7 @@ static int tegra_otg_probe(struct platform_device *pdev)
tegra->otg.set_suspend = tegra_otg_set_suspend;
tegra->otg.set_power = tegra_otg_set_power;
spin_lock_init(&tegra->lock);
+ mutex_init(&tegra->irq_work_mutex);
if (pdata) {
tegra->builtin_host = !pdata->ehci_pdata->builtin_host_disabled;
@@ -498,6 +518,7 @@ static int __exit tegra_otg_remove(struct platform_device *pdev)
clk_disable(tegra->clk);
clk_put(tegra->clk);
platform_set_drvdata(pdev, NULL);
+ mutex_destroy(&tegra->irq_work_mutex);
kfree(tegra);
return 0;
@@ -510,6 +531,8 @@ static int tegra_otg_suspend(struct device *dev)
struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
struct otg_transceiver *otg = &tegra->otg;
int val;
+
+ mutex_lock(&tegra->irq_work_mutex);
DBG("%s(%d) BEGIN state : %s\n", __func__, __LINE__,
tegra_state_name(otg->state));
@@ -526,6 +549,7 @@ static int tegra_otg_suspend(struct device *dev)
tegra->suspended = true;
DBG("%s(%d) END\n", __func__, __LINE__);
+ mutex_unlock(&tegra->irq_work_mutex);
return 0;
}
@@ -533,13 +557,15 @@ static void tegra_otg_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
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__);
- if (!tegra->suspended)
+ mutex_lock(&tegra->irq_work_mutex);
+ if (!tegra->suspended) {
+ mutex_unlock(&tegra->irq_work_mutex);
return;
+ }
/* Clear pending interrupts */
clk_enable(tegra->clk);
@@ -548,10 +574,6 @@ static void tegra_otg_resume(struct device *dev)
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)
@@ -561,13 +583,13 @@ static void tegra_otg_resume(struct device *dev)
USB_ID_PIN_WAKEUP_EN;
spin_unlock_irqrestore(&tegra->lock, flags);
- irq_work(&tegra->work);
-
+ schedule_work(&tegra->work);
enable_interrupt(tegra, true);
tegra->suspended = false;
DBG("%s(%d) END\n", __func__, __LINE__);
+ mutex_unlock(&tegra->irq_work_mutex);
}
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 96db92715207..c4eda3fe1ab7 100644
--- a/drivers/usb/serial/baseband_usb_chr.c
+++ b/drivers/usb/serial/baseband_usb_chr.c
@@ -74,6 +74,13 @@ static struct workqueue_struct *chr_ipc_wq;
static atomic_t g_rx_count = ATOMIC_INIT(0);
+struct usb_chr_resource {
+ unsigned char *ipc_rx;
+ unsigned char *ipc_tx;
+ unsigned char *rx_buf;
+};
+static struct usb_chr_resource usb_chr_res;
+
/* baseband ipc functions */
static void baseband_ipc_dump(const char *prefix, unsigned long int offset,
@@ -521,9 +528,7 @@ static void baseband_ipc_close(struct baseband_ipc *ipc)
memset(&ipc->rx.wait, 0, sizeof(ipc->rx.wait));
/* destroy data buffers */
- kfree(ipc->ipc_tx);
ipc->ipc_tx = (unsigned char *) 0;
- kfree(ipc->ipc_rx);
ipc->ipc_rx = (unsigned char *) 0;
list_for_each_entry_safe(ipc_buf, ipc_buf_next, &ipc->tx_free.buf, list)
{
@@ -601,16 +606,14 @@ static struct baseband_ipc *baseband_ipc_open(work_func_t work_func,
ipc_buf);
list_add_tail(&ipc_buf->list, &ipc->tx_free.buf);
}
- ipc->ipc_rx = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+ ipc->ipc_rx = usb_chr_res.ipc_rx;
if (!ipc->ipc_rx) {
- pr_err("baseband_ipc_open - "
- "cannot allocate ipc->ipc_rx\n");
+ pr_err("%s: cannot find ipc->ipc_rx\n", __func__);
goto error_exit;
}
- ipc->ipc_tx = kmalloc(USB_CHR_TX_BUFSIZ, GFP_KERNEL);
+ ipc->ipc_tx = usb_chr_res.ipc_tx;
if (!ipc->ipc_tx) {
- pr_err("baseband_ipc_open - "
- "cannot allocate ipc->ipc_tx\n");
+ pr_err("%s: cannot find ipc->ipc_tx\n", __func__);
goto error_exit;
}
@@ -867,6 +870,7 @@ static void baseband_usb_driver_disconnect(struct usb_interface *intf)
&& baseband_usb_chr->ipc->workqueue)
flush_workqueue(baseband_usb_chr->ipc->workqueue);
usb_device_connection = false;
+ probe_usb_intf = NULL;
}
pr_debug("%s(%d) }\n", __func__, __LINE__);
}
@@ -956,7 +960,6 @@ static void baseband_usb_close(struct baseband_usb *usb)
usb_kill_urb(usb->usb.rx_urb);
if (usb->usb.rx_urb->transfer_buffer) {
pr_debug("%s: free rx urb transfer buffer\n", __func__);
- kfree(usb->usb.rx_urb->transfer_buffer);
usb->usb.rx_urb->transfer_buffer = (void *) 0;
}
}
@@ -966,13 +969,6 @@ static void baseband_usb_close(struct baseband_usb *usb)
flush_work_sync(&usb->ipc->rx_work);
}
- /* close usb driver */
- if (usb->usb.driver) {
- pr_debug("close usb driver {\n");
- usb_deregister(usb->usb.driver);
- usb->usb.driver = (struct usb_driver *) 0;
- pr_debug("close usb driver }\n");
- }
/* close baseband ipc */
if (usb->ipc) {
@@ -1014,24 +1010,17 @@ static struct baseband_usb *baseband_usb_open(work_func_t work_func,
goto error_exit;
}
- /* open usb driver */
- probe_usb_intf = (struct usb_interface *) 0;
usb->usb.driver = &baseband_usb_driver;
- err = usb_register(&baseband_usb_driver);
- if (err < 0) {
- pr_err("cannot open usb driver - err %d\n", err);
- goto error_exit;
- }
- /* wait for probe */
- pr_info("%s: waiting for usb probe...\n", __func__);
- for (i = 0; i < 5 * 10; i++) {
+ for (i = 0; i < 5 * 50; i++) {
if (probe_usb_intf && usb_device_connection)
break;
- msleep(100);
+ /* wait for probe */
+ pr_debug("%s: waiting for usb probe...\n", __func__);
+ msleep(20);
}
if (!probe_usb_intf || !usb_device_connection) {
- pr_info("%s: probe timed out!\n", __func__);
+ pr_err("%s: probe timed out!\n", __func__);
goto error_exit;
}
@@ -1066,9 +1055,9 @@ static struct baseband_usb *baseband_usb_open(work_func_t work_func,
pr_err("usb_alloc_urb() failed\n");
goto error_exit;
}
- buf = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+ buf = usb_chr_res.rx_buf;
if (!buf) {
- pr_err("%s: usb buffer kmalloc() failed\n", __func__);
+ pr_err("%s: usb rx buffer not found\n", __func__);
usb_free_urb(urb);
goto error_exit;
}
@@ -1222,17 +1211,33 @@ static const struct file_operations baseband_usb_chr_fops = {
static int baseband_usb_chr_init(void)
{
- int err;
+ int err = -ENOMEM;
pr_debug("baseband_usb_chr_init {\n");
+ usb_chr_res.ipc_rx = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+ if (!usb_chr_res.ipc_rx) {
+ pr_err("cannot allocate ipc_rx\n");
+ goto error;
+ }
+ usb_chr_res.ipc_tx = kmalloc(USB_CHR_TX_BUFSIZ, GFP_KERNEL);
+ if (!usb_chr_res.ipc_tx) {
+ pr_err("cannot allocate ipc_tx\n");
+ goto error;
+ }
+ usb_chr_res.rx_buf = kmalloc(USB_CHR_RX_BUFSIZ, GFP_KERNEL);
+ if (!usb_chr_res.rx_buf) {
+ pr_err("%s: usb buffer kmalloc() failed\n", __func__);
+ goto error;
+ }
+
/* register character device */
err = register_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
BASEBAND_USB_CHR_DEV_NAME,
&baseband_usb_chr_fops);
if (err < 0) {
pr_err("cannot register character device - %d\n", err);
- return err;
+ goto error;
}
pr_debug("registered baseband usb character device - major %d\n",
BASEBAND_USB_CHR_DEV_MAJOR);
@@ -1243,11 +1248,30 @@ static int baseband_usb_chr_init(void)
pr_err("cannot create workqueue\n");
unregister_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
BASEBAND_USB_CHR_DEV_NAME);
- return -ENODEV;
+ err = -ENODEV;
+ goto error;
+ }
+
+ /* register usb driver */
+ err = usb_register(&baseband_usb_driver);
+ if (err < 0) {
+ pr_err("%s: cannot register usb driver %d\n", __func__, err);
+ goto error2;
}
pr_debug("baseband_usb_chr_init }\n");
return 0;
+
+error2:
+ unregister_chrdev(BASEBAND_USB_CHR_DEV_MAJOR,
+ BASEBAND_USB_CHR_DEV_NAME);
+ destroy_workqueue(chr_ipc_wq);
+ chr_ipc_wq = NULL;
+error:
+ kfree(usb_chr_res.ipc_rx);
+ kfree(usb_chr_res.ipc_tx);
+ kfree(usb_chr_res.rx_buf);
+ return err;
}
static void baseband_usb_chr_exit(void)
@@ -1262,6 +1286,14 @@ static void baseband_usb_chr_exit(void)
destroy_workqueue(chr_ipc_wq);
chr_ipc_wq = NULL;
}
+
+ /* close usb driver */
+ usb_deregister(&baseband_usb_driver);
+
+ kfree(usb_chr_res.ipc_rx);
+ kfree(usb_chr_res.ipc_tx);
+ kfree(usb_chr_res.rx_buf);
+
pr_debug("baseband_usb_chr_exit }\n");
}
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index debd41c9313e..400cf43c5972 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
+CFLAGS_tegra_pwm_bl.o = -Werror
obj-$(CONFIG_BACKLIGHT_TEGRA_PWM) += tegra_pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
index b5540a5793b2..68cf54264403 100644
--- a/drivers/video/tegra/Kconfig
+++ b/drivers/video/tegra/Kconfig
@@ -119,7 +119,7 @@ config NVMAP_PAGE_POOL_SIZE
default 0x0
config NVMAP_CACHE_MAINT_BY_SET_WAYS
- bool "Enalbe cache maintenance by set/ways"
+ bool "Enable cache maintenance by set/ways"
depends on TEGRA_NVMAP
help
Say Y here to reduce cache maintenance overhead by MVA.
@@ -127,6 +127,14 @@ config NVMAP_CACHE_MAINT_BY_SET_WAYS
where inner cache includes only L1. For the systems, where inner cache
includes L1 and L2, keep this option disabled.
+config NVMAP_OUTER_CACHE_MAINT_BY_SET_WAYS
+ bool "Enable outer cache maintenance by set/ways"
+ depends on TEGRA_NVMAP
+ help
+ Say Y here if you want to optimize cache maintenance for ranges
+ bigger than size of outer cache. This option has no effect on
+ system without outer cache.
+
config NVMAP_VPR
bool "Enable VPR Heap."
depends on TEGRA_NVMAP
@@ -135,6 +143,15 @@ config NVMAP_VPR
Say Y here to enable Video Protection Region(VPR) heap.
if unsure, say N.
+config NVMAP_FORCE_ZEROED_USER_PAGES
+ bool "Only alloc zeroed pages for user space"
+ depends on TEGRA_NVMAP
+ help
+ Say Y here to force zeroing of pages allocated for user space. This
+ avoids leaking kernel secure data to user space. This can add
+ significant overhead to allocation operations depending on the
+ allocation size requested.
+
config TEGRA_DSI
bool "Enable DSI panel."
default n
diff --git a/drivers/video/tegra/dc/csc.c b/drivers/video/tegra/dc/csc.c
index 74fa900352a1..09db5fee4c6f 100644
--- a/drivers/video/tegra/dc/csc.c
+++ b/drivers/video/tegra/dc/csc.c
@@ -54,10 +54,12 @@ int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
return -EFAULT;
}
+ tegra_dc_hold_dc_out(dc);
tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
DC_CMD_DISPLAY_WINDOW_HEADER);
tegra_dc_set_csc(dc, &dc->windows[win_idx].csc);
+ tegra_dc_release_dc_out(dc);
mutex_unlock(&dc->lock);
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 1f7e2ce67682..d01df2f520b8 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -82,7 +82,7 @@ struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
DEFINE_MUTEX(tegra_dc_lock);
DEFINE_MUTEX(shared_lock);
-static inline void tegra_dc_clk_enable(struct tegra_dc *dc)
+void tegra_dc_clk_enable(struct tegra_dc *dc)
{
if (!tegra_is_clk_enabled(dc->clk)) {
clk_enable(dc->clk);
@@ -90,7 +90,7 @@ static inline void tegra_dc_clk_enable(struct tegra_dc *dc)
}
}
-static inline void tegra_dc_clk_disable(struct tegra_dc *dc)
+void tegra_dc_clk_disable(struct tegra_dc *dc)
{
if (tegra_is_clk_enabled(dc->clk)) {
clk_disable(dc->clk);
@@ -98,6 +98,18 @@ static inline void tegra_dc_clk_disable(struct tegra_dc *dc)
}
}
+void tegra_dc_hold_dc_out(struct tegra_dc *dc)
+{
+ if (dc->out_ops->hold)
+ dc->out_ops->hold(dc);
+}
+
+void tegra_dc_release_dc_out(struct tegra_dc *dc)
+{
+ if (dc->out_ops->release)
+ dc->out_ops->release(dc);
+}
+
#define DUMP_REG(a) do { \
snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
#a, a, tegra_dc_readl(dc, a)); \
@@ -121,8 +133,9 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
int i;
char buff[256];
+ mutex_lock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
tegra_dc_io_start(dc);
- tegra_dc_clk_enable(dc);
DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
DUMP_REG(DC_CMD_DISPLAY_COMMAND);
@@ -272,8 +285,9 @@ static void _dump_regs(struct tegra_dc *dc, void *data,
DUMP_REG(DC_COM_PM1_DUTY_CYCLE);
DUMP_REG(DC_DISP_SD_CONTROL);
- tegra_dc_clk_disable(dc);
tegra_dc_io_end(dc);
+ tegra_dc_release_dc_out(dc);
+ mutex_unlock(&dc->lock);
}
#undef DUMP_REG
@@ -488,9 +502,13 @@ int tegra_dc_get_stride(struct tegra_dc *dc, unsigned win)
if (!dc->enabled)
return 0;
BUG_ON(win > DC_N_WINDOWS);
+ mutex_lock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
tegra_dc_writel(dc, WINDOW_A_SELECT << win,
DC_CMD_DISPLAY_WINDOW_HEADER);
stride = tegra_dc_readl(dc, DC_WIN_LINE_STRIDE);
+ tegra_dc_release_dc_out(dc);
+ mutex_unlock(&dc->lock);
return GET_LINE_STRIDE(stride);
}
EXPORT_SYMBOL(tegra_dc_get_stride);
@@ -550,17 +568,6 @@ static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
}
}
-void tegra_dc_host_suspend(struct tegra_dc *dc)
-{
- tegra_dsi_host_suspend(dc);
- tegra_dc_clk_disable(dc);
-}
-
-void tegra_dc_host_resume(struct tegra_dc *dc) {
- tegra_dc_clk_enable(dc);
- tegra_dsi_host_resume(dc);
-}
-
static inline void disable_dc_irq(unsigned int irq)
{
disable_irq(irq);
@@ -577,9 +584,11 @@ u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i)
u32 max;
mutex_lock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
max = nvhost_syncpt_incr_max_ext(dc->ndev,
dc->syncpt[i].id, ((dc->enabled) ? 1 : 0));
dc->syncpt[i].max = max;
+ tegra_dc_release_dc_out(dc);
mutex_unlock(&dc->lock);
return max;
@@ -588,11 +597,14 @@ u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i)
void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val)
{
mutex_lock(&dc->lock);
- if ( dc->enabled )
+ if (dc->enabled) {
+ tegra_dc_hold_dc_out(dc);
while (dc->syncpt[i].min < val) {
dc->syncpt[i].min++;
nvhost_syncpt_cpu_incr_ext(dc->ndev, dc->syncpt[i].id);
}
+ tegra_dc_release_dc_out(dc);
+ }
mutex_unlock(&dc->lock);
}
@@ -609,8 +621,7 @@ 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);
+ tegra_dc_hold_dc_out(dc);
ctrl = ((cfg->period << PM_PERIOD_SHIFT) |
(cfg->clk_div << PM_CLK_DIVIDER_SHIFT) |
@@ -644,6 +655,7 @@ tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
break;
}
tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS);
+ tegra_dc_release_dc_out(dc);
mutex_unlock(&dc->lock);
}
EXPORT_SYMBOL(tegra_dc_config_pwm);
@@ -790,6 +802,9 @@ EXPORT_SYMBOL(tegra_dc_get_out_max_pixclock);
void tegra_dc_enable_crc(struct tegra_dc *dc)
{
u32 val;
+
+ mutex_lock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
tegra_dc_io_start(dc);
val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA |
@@ -797,15 +812,21 @@ void tegra_dc_enable_crc(struct tegra_dc *dc)
tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL);
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ tegra_dc_release_dc_out(dc);
+ mutex_unlock(&dc->lock);
}
void tegra_dc_disable_crc(struct tegra_dc *dc)
{
+ mutex_lock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL);
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
tegra_dc_io_end(dc);
+ tegra_dc_release_dc_out(dc);
+ mutex_unlock(&dc->lock);
}
u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
@@ -821,7 +842,11 @@ u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
* DC_COM_CRC_CHECKSUM_LATCHED is available after VBLANK */
mdelay(TEGRA_CRC_LATCHED_DELAY);
+ mutex_lock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
crc = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM_LATCHED);
+ tegra_dc_release_dc_out(dc);
+ mutex_unlock(&dc->lock);
crc_error:
return crc;
}
@@ -848,6 +873,36 @@ static inline void enable_dc_irq(unsigned int irq)
#endif
}
+void tegra_dc_get_fbvblank(struct tegra_dc *dc, struct fb_vblank *vblank)
+{
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ vblank->flags = FB_VBLANK_HAVE_VSYNC;
+}
+
+int tegra_dc_wait_for_vsync(struct tegra_dc *dc)
+{
+ int ret = -ENOTTY;
+
+ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) || !dc->enabled)
+ return ret;
+
+ /*
+ * Logic is as follows
+ * a) Indicate we need a vblank.
+ * b) Wait for completion to be signalled from isr.
+ * c) Initialize completion for next iteration.
+ */
+
+ tegra_dc_hold_dc_out(dc);
+ dc->out->user_needs_vblank = true;
+
+ ret = wait_for_completion_interruptible(&dc->out->user_vblank_comp);
+ init_completion(&dc->out->user_vblank_comp);
+ tegra_dc_release_dc_out(dc);
+
+ return ret;
+}
+
static void tegra_dc_vblank(struct work_struct *work)
{
struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work);
@@ -860,6 +915,7 @@ static void tegra_dc_vblank(struct work_struct *work)
return;
}
+ tegra_dc_hold_dc_out(dc);
/* 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))
@@ -886,6 +942,7 @@ static void tegra_dc_vblank(struct work_struct *work)
if (!dc->vblank_ref_count)
tegra_dc_mask_interrupt(dc, V_BLANK_INT);
+ tegra_dc_release_dc_out(dc);
mutex_unlock(&dc->lock);
/* Do the actual brightness update outside of the mutex */
@@ -908,8 +965,8 @@ static void tegra_dc_one_shot_worker(struct work_struct *work)
/* 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);
+ if (dc->out_ops->idle)
+ dc->out_ops->idle(dc);
mutex_unlock(&dc->lock);
}
@@ -962,9 +1019,9 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
if (dc->windows[i].underflows > 4) {
- printk("%s:dc in underflow state."
+ trace_printk("%s:window %c in underflow state."
" enable UF_LINE_FLUSH to clear up\n",
- __func__);
+ dc->ndev->name, (65 + i));
tegra_dc_writel(dc, UF_LINE_FLUSH,
DC_DISP_DISP_MISC_CONTROL);
tegra_dc_writel(dc, GENERAL_UPDATE,
@@ -996,6 +1053,13 @@ static void tegra_dc_underflow_handler(struct tegra_dc *dc)
#ifndef CONFIG_TEGRA_FPGA_PLATFORM
static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
{
+ /* pending user vblank, so wakeup */
+ if ((status & (V_BLANK_INT | MSF_INT)) &&
+ (dc->out->user_needs_vblank)) {
+ dc->out->user_needs_vblank = false;
+ complete(&dc->out->user_vblank_comp);
+ }
+
if (status & V_BLANK_INT) {
/* Sync up windows. */
tegra_dc_trigger_windows(dc);
@@ -1018,6 +1082,10 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
queue_work(system_freezable_wq, &dc->vblank_work);
if (status & FRAME_END_INT) {
+ struct timespec tm = CURRENT_TIME;
+ dc->frame_end_timestamp = timespec_to_ns(&tm);
+ wake_up(&dc->timestamp_wq);
+
/* Mark the frame_end as complete. */
if (!completion_done(&dc->frame_end_complete))
complete(&dc->frame_end_complete);
@@ -1025,6 +1093,22 @@ static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
tegra_dc_trigger_windows(dc);
}
}
+
+/* XXX: Not sure if we limit look ahead to 1 frame */
+bool tegra_dc_is_within_n_vsync(struct tegra_dc *dc, s64 ts)
+{
+ BUG_ON(!dc->frametime_ns);
+ return ((ts - dc->frame_end_timestamp) < dc->frametime_ns);
+}
+
+bool tegra_dc_does_vsync_separate(struct tegra_dc *dc, s64 new_ts, s64 old_ts)
+{
+ BUG_ON(!dc->frametime_ns);
+ return (((new_ts - old_ts) > dc->frametime_ns)
+ || (div_s64((new_ts - dc->frame_end_timestamp), dc->frametime_ns)
+ != div_s64((old_ts - dc->frame_end_timestamp),
+ dc->frametime_ns)));
+}
#endif
static irqreturn_t tegra_dc_irq(int irq, void *ptr)
@@ -1187,6 +1271,7 @@ static u32 get_syncpt(struct tegra_dc *dc, int idx)
static int tegra_dc_init(struct tegra_dc *dc)
{
int i;
+ int int_enable;
tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
if (dc->ndev->id == 0) {
@@ -1222,8 +1307,12 @@ static int tegra_dc_init(struct tegra_dc *dc)
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);
+ int_enable = (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
+ /* for panels with one-shot mode enable tearing effect interrupt */
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ int_enable |= MSF_INT;
+
+ tegra_dc_writel(dc, int_enable, DC_CMD_INT_ENABLE);
tegra_dc_writel(dc, ALL_UF_INT, DC_CMD_INT_MASK);
tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
@@ -1272,14 +1361,18 @@ static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
tegra_dc_clk_enable(dc);
/* do not accept interrupts during initialization */
- tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE);
tegra_dc_writel(dc, 0, DC_CMD_INT_MASK);
enable_dc_irq(dc->irq);
failed_init = tegra_dc_init(dc);
if (failed_init) {
- _tegra_dc_controller_disable(dc);
+ tegra_dc_writel(dc, 0, DC_CMD_INT_MASK);
+ disable_irq(dc->irq);
+ tegra_dc_clear_bandwidth(dc);
+ tegra_dc_clk_disable(dc);
+ if (dc->out && dc->out->disable)
+ dc->out->disable();
return false;
}
@@ -1367,19 +1460,14 @@ static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
static int _tegra_dc_set_default_videomode(struct tegra_dc *dc)
{
- return tegra_dc_set_fb_mode(dc, &tegra_dc_hdmi_fallback_mode, 0);
-}
-
-static bool _tegra_dc_enable(struct tegra_dc *dc)
-{
if (dc->mode.pclk == 0) {
switch (dc->out->type) {
case TEGRA_DC_OUT_HDMI:
/* DC enable called but no videomode is loaded.
Check if HDMI is connected, then set fallback mdoe */
if (tegra_dc_hpd(dc)) {
- if (_tegra_dc_set_default_videomode(dc))
- return false;
+ return tegra_dc_set_fb_mode(dc,
+ &tegra_dc_hdmi_fallback_mode, 0);
} else
return false;
@@ -1395,12 +1483,24 @@ static bool _tegra_dc_enable(struct tegra_dc *dc)
}
}
+ return false;
+}
+
+static bool _tegra_dc_enable(struct tegra_dc *dc)
+{
+ if (dc->mode.pclk == 0)
+ return false;
+
if (!dc->out)
return false;
tegra_dc_io_start(dc);
- return _tegra_dc_controller_enable(dc);
+ if (!_tegra_dc_controller_enable(dc)) {
+ tegra_dc_io_end(dc);
+ return false;
+ }
+ return true;
}
void tegra_dc_enable(struct tegra_dc *dc)
@@ -1505,8 +1605,20 @@ void tegra_dc_blank(struct tegra_dc *dc)
static void _tegra_dc_disable(struct tegra_dc *dc)
{
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
+ mutex_lock(&dc->one_shot_lock);
+ cancel_delayed_work_sync(&dc->one_shot_work);
+ }
+
+ tegra_dc_hold_dc_out(dc);
+
_tegra_dc_controller_disable(dc);
tegra_dc_io_end(dc);
+
+ tegra_dc_release_dc_out(dc);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ mutex_unlock(&dc->one_shot_lock);
}
void tegra_dc_disable(struct tegra_dc *dc)
@@ -1516,16 +1628,9 @@ void tegra_dc_disable(struct tegra_dc *dc)
/* it's important that new underflow work isn't scheduled before the
* lock is acquired. */
cancel_delayed_work_sync(&dc->underflow_work);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
- mutex_lock(&dc->one_shot_lock);
- cancel_delayed_work_sync(&dc->one_shot_work);
- }
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;
@@ -1538,8 +1643,6 @@ void tegra_dc_disable(struct tegra_dc *dc)
#endif
mutex_unlock(&dc->lock);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
- mutex_unlock(&dc->one_shot_lock);
print_mode_info(dc, dc->mode);
}
@@ -1605,12 +1708,12 @@ 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);
+ tegra_dc_hold_dc_out(dc);
if (dc->enabled) {
tegra_dc_underflow_handler(dc);
}
+ tegra_dc_release_dc_out(dc);
mutex_unlock(&dc->lock);
}
@@ -1721,6 +1824,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev,
mutex_init(&dc->one_shot_lock);
init_completion(&dc->frame_end_complete);
init_waitqueue_head(&dc->wq);
+ init_waitqueue_head(&dc->timestamp_wq);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
#endif
@@ -1772,8 +1876,10 @@ static int tegra_dc_probe(struct nvhost_device *ndev,
}
mutex_lock(&dc->lock);
- if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
+ if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED) {
+ _tegra_dc_set_default_videomode(dc);
dc->enabled = _tegra_dc_enable(dc);
+ }
mutex_unlock(&dc->lock);
/* interrupt handler must be registered before tegra_fb_register() */
@@ -1789,7 +1895,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev,
dev_info(&ndev->dev, "probed\n");
if (dc->pdata->fb) {
- if (dc->pdata->fb->bits_per_pixel == -1) {
+ if (dc->enabled && dc->pdata->fb->bits_per_pixel == -1) {
unsigned long fmt;
tegra_dc_writel(dc,
WINDOW_A_SELECT << dc->pdata->fb->win,
@@ -1921,8 +2027,10 @@ static int tegra_dc_resume(struct nvhost_device *ndev)
mutex_lock(&dc->lock);
dc->suspended = false;
- if (dc->enabled)
+ if (dc->enabled) {
+ _tegra_dc_set_default_videomode(dc);
_tegra_dc_enable(dc);
+ }
if (dc->out && dc->out->hotplug_init)
dc->out->hotplug_init();
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index fb1243593587..75c3a2a29658 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -75,6 +75,12 @@ struct tegra_dc_out_ops {
void (*enable)(struct tegra_dc *dc);
/* disable output. dc clocks are on at this point */
void (*disable)(struct tegra_dc *dc);
+ /* hold output. keeps dc clocks on. */
+ void (*hold)(struct tegra_dc *dc);
+ /* release output. dc clocks may turn off after this. */
+ void (*release)(struct tegra_dc *dc);
+ /* idle routine of output. dc clocks may turn off after this. */
+ void (*idle)(struct tegra_dc *dc);
/* suspend output. dc clocks are on at this point */
void (*suspend)(struct tegra_dc *dc);
/* resume output. dc clocks are on at this point */
@@ -107,12 +113,14 @@ struct tegra_dc {
void *out_data;
struct tegra_dc_mode mode;
+ s64 frametime_ns;
struct tegra_dc_win windows[DC_N_WINDOWS];
struct tegra_dc_blend blend;
int n_windows;
wait_queue_head_t wq;
+ wait_queue_head_t timestamp_wq;
struct mutex lock;
struct mutex one_shot_lock;
@@ -157,6 +165,7 @@ struct tegra_dc {
struct delayed_work underflow_work;
u32 one_shot_delay_ms;
struct delayed_work one_shot_work;
+ s64 frame_end_timestamp;
};
#define print_mode_info(dc, mode) do { \
@@ -366,9 +375,17 @@ 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);
-/* defined in dc.c, used in bandwidth.c */
+/* defined in dc.c, used in bandwidth.c and ext/dev.c */
unsigned int tegra_dc_has_multiple_dc(void);
+/* defined in dc.c, used in dsi.c */
+void tegra_dc_clk_enable(struct tegra_dc *dc);
+void tegra_dc_clk_disable(struct tegra_dc *dc);
+
+/* defined in dc.c, used in nvsd.c and dsi.c */
+void tegra_dc_hold_dc_out(struct tegra_dc *dc);
+void tegra_dc_release_dc_out(struct tegra_dc *dc);
+
/* 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);
diff --git a/drivers/video/tegra/dc/dc_sysfs.c b/drivers/video/tegra/dc/dc_sysfs.c
index bf27e963f233..09a8e2dbb5b1 100644
--- a/drivers/video/tegra/dc/dc_sysfs.c
+++ b/drivers/video/tegra/dc/dc_sysfs.c
@@ -313,6 +313,14 @@ static ssize_t nvdps_store(struct device *dev,
static DEVICE_ATTR(nvdps, S_IRUGO|S_IWUSR, nvdps_show, nvdps_store);
+static ssize_t smart_panel_show(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "1\n");
+}
+
+static DEVICE_ATTR(smart_panel, S_IRUGO, smart_panel_show, NULL);
+
void __devexit tegra_dc_remove_sysfs(struct device *dev)
{
struct nvhost_device *ndev = to_nvhost_device(dev);
@@ -332,6 +340,9 @@ void __devexit tegra_dc_remove_sysfs(struct device *dev)
if (sd_settings)
nvsd_remove_sysfs(dev);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ device_remove_file(dev, &dev_attr_smart_panel);
}
void tegra_dc_create_sysfs(struct device *dev)
@@ -355,6 +366,9 @@ void tegra_dc_create_sysfs(struct device *dev)
if (sd_settings)
error |= nvsd_create_sysfs(dev);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ error |= device_create_file(dev, &dev_attr_smart_panel);
+
if (error)
dev_err(&ndev->dev, "Failed to create sysfs attributes!\n");
}
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
index 7ee9375f58f1..d3b1d40d535b 100644
--- a/drivers/video/tegra/dc/dsi.c
+++ b/drivers/video/tegra/dc/dsi.c
@@ -79,6 +79,8 @@
#define DSI_LP_OP_WRITE 0x1
#define DSI_LP_OP_READ 0x2
+#define DSI_HOST_IDLE_PERIOD 1000
+
static bool enable_read_debug;
module_param(enable_read_debug, bool, 0644);
MODULE_PARM_DESC(enable_read_debug,
@@ -129,6 +131,11 @@ struct tegra_dc_dsi_data {
bool ulpm;
bool enabled;
bool host_suspended;
+ struct mutex host_resume_lock;
+ struct delayed_work idle_work;
+ unsigned long idle_delay;
+ spinlock_t host_ref_lock;
+ u8 host_ref;
u8 driven_mode;
u8 controller_index;
@@ -294,6 +301,10 @@ const u32 init_reg[] = {
DSI_PKT_LEN_6_7,
};
+static int tegra_dsi_host_suspend(struct tegra_dc *dc);
+static int tegra_dsi_host_resume(struct tegra_dc *dc);
+static void tegra_dc_dsi_idle_work(struct work_struct *work);
+
inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
{
unsigned long ret;
@@ -331,6 +342,7 @@ static int dbg_dsi_show(struct seq_file *s, void *unused)
DUMP_REG(DSI_CTXSW);
DUMP_REG(DSI_POWER_CONTROL);
DUMP_REG(DSI_INT_ENABLE);
+ DUMP_REG(DSI_HOST_DSI_CONTROL);
DUMP_REG(DSI_CONTROL);
DUMP_REG(DSI_SOL_DELAY);
DUMP_REG(DSI_MAX_THRESHOLD);
@@ -650,6 +662,13 @@ static void tegra_dsi_init_sw(struct tegra_dc *dc,
dsi->info.video_clock_mode = TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS;
}
+ dsi->host_ref = 0;
+ dsi->host_suspended = false;
+ spin_lock_init(&dsi->host_ref_lock);
+ mutex_init(&dsi->host_resume_lock);
+ init_completion(&dc->out->user_vblank_comp);
+ INIT_DELAYED_WORK(&dsi->idle_work, tegra_dc_dsi_idle_work);
+ dsi->idle_delay = msecs_to_jiffies(DSI_HOST_IDLE_PERIOD);
}
#define SELECT_T_PHY(platform_t_phy_ns, default_phy, clk_ns, hw_inc) ( \
@@ -1341,9 +1360,38 @@ static void tegra_dsi_reset_underflow_overflow
}
}
+static void tegra_dsi_soft_reset(struct tegra_dc_dsi_data *dsi)
+{
+ u32 trigger;
+
+ tegra_dsi_writel(dsi,
+ DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE),
+ DSI_POWER_CONTROL);
+ /* stabilization delay */
+ udelay(300);
+
+ tegra_dsi_writel(dsi,
+ DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE),
+ DSI_POWER_CONTROL);
+ /* stabilization delay */
+ udelay(300);
+
+ /* dsi HW does not clear host trigger bit automatically
+ * on dsi interface disable if host fifo is empty or in mid
+ * of host transmission
+ */
+ trigger = tegra_dsi_readl(dsi, DSI_TRIGGER);
+ if (trigger)
+ tegra_dsi_writel(dsi, 0x0, DSI_TRIGGER);
+}
+
static void tegra_dsi_stop_dc_stream(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi)
{
+ /* Mask the MSF interrupt. */
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ tegra_dc_mask_interrupt(dc, MSF_INT);
+
tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND);
tegra_dc_writel(dc, 0, DC_DISP_DISP_WIN_OPTIONS);
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
@@ -1359,13 +1407,13 @@ static void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc,
long timeout;
u32 frame_period = DIV_ROUND_UP(S_TO_MS(1), dsi->info.refresh_rate);
- /* stop dc */
- tegra_dsi_stop_dc_stream(dc, dsi);
+ INIT_COMPLETION(dc->frame_end_complete);
- /* enable frame end interrupt */
+ /* unmask frame end interrupt */
val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val |= FRAME_END_INT;
- tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
+ tegra_dc_writel(dc, val | FRAME_END_INT, DC_CMD_INT_MASK);
+
+ tegra_dsi_stop_dc_stream(dc, dsi);
/* wait for frame_end completion.
* timeout is 2 frame duration to accomodate for
@@ -1375,9 +1423,14 @@ static void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc,
&dc->frame_end_complete,
msecs_to_jiffies(2 * frame_period));
- /* disable frame end interrupt */
- val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
- val &= ~FRAME_END_INT;
+ /* give 2 line time to dsi HW to catch up
+ * with pixels sent by dc
+ */
+ udelay(50);
+
+ tegra_dsi_soft_reset(dsi);
+
+ /* reinstate interrupt mask */
tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
if (timeout == 0)
@@ -1419,6 +1472,9 @@ static void tegra_dsi_start_dc_stream(struct tegra_dc *dc,
tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ | NC_HOST_TRIG,
DC_CMD_STATE_CONTROL);
+
+ /* Unmask the MSF interrupt. */
+ tegra_dc_unmask_interrupt(dc, MSF_INT);
} else {
/* set continuous mode */
tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY,
@@ -1559,7 +1615,8 @@ static void tegra_dsi_set_control_reg_lp(struct tegra_dc_dsi_data *dsi)
dsi->status.vtype = DSI_VIDEO_TYPE_NOT_INIT;
}
-static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi)
+static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi,
+ u8 driven_mode)
{
u32 dsi_control;
u32 host_dsi_control;
@@ -1571,7 +1628,7 @@ static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi)
max_threshold = 0;
dcs_cmd = 0;
- if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) {
+ if (driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) {
dsi_control |= DSI_CTRL_HOST_DRIVEN;
host_dsi_control |= HOST_DSI_CTRL_HOST_DRIVEN;
max_threshold =
@@ -1583,17 +1640,19 @@ static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi)
max_threshold =
DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_VIDEO_FIFO_DEPTH);
dsi->status.driven = DSI_DRIVEN_MODE_DC;
- }
- if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE) {
- dsi_control |= DSI_CTRL_CMD_MODE;
- dcs_cmd = DSI_DCS_CMDS_LT5_DCS_CMD(DSI_WRITE_MEMORY_START)|
- DSI_DCS_CMDS_LT3_DCS_CMD(DSI_WRITE_MEMORY_CONTINUE);
- dsi->status.vtype = DSI_VIDEO_TYPE_CMD_MODE;
-
- } else {
- dsi_control |= DSI_CTRL_VIDEO_MODE;
- dsi->status.vtype = DSI_VIDEO_TYPE_VIDEO_MODE;
+ if (dsi->info.video_data_type ==
+ TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE) {
+ dsi_control |= DSI_CTRL_CMD_MODE;
+ dcs_cmd = DSI_DCS_CMDS_LT5_DCS_CMD(
+ DSI_WRITE_MEMORY_START)|
+ DSI_DCS_CMDS_LT3_DCS_CMD(
+ DSI_WRITE_MEMORY_CONTINUE);
+ dsi->status.vtype = DSI_VIDEO_TYPE_CMD_MODE;
+ } else {
+ dsi_control |= DSI_CTRL_VIDEO_MODE;
+ dsi->status.vtype = DSI_VIDEO_TYPE_VIDEO_MODE;
+ }
}
tegra_dsi_writel(dsi, max_threshold, DSI_MAX_THRESHOLD);
@@ -1734,6 +1793,7 @@ static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
dsi->status.lphs = DSI_LPHS_IN_LP_MODE;
dsi->status.lp_op = lp_op;
+ dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_HOST;
success:
err = 0;
fail:
@@ -1741,7 +1801,8 @@ fail:
}
static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc,
- struct tegra_dc_dsi_data *dsi)
+ struct tegra_dc_dsi_data *dsi,
+ u8 driven_mode)
{
int err;
@@ -1750,9 +1811,12 @@ static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc,
goto fail;
}
- if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE)
+ if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE &&
+ dsi->driven_mode == driven_mode)
goto success;
+ dsi->driven_mode = driven_mode;
+
if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
@@ -1767,14 +1831,14 @@ static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc,
tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_HS_MODE);
- if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_DC) {
+ if (driven_mode == TEGRA_DSI_DRIVEN_BY_DC) {
tegra_dsi_set_pkt_seq(dc, dsi);
tegra_dsi_set_pkt_length(dc, dsi);
tegra_dsi_set_sol_delay(dc, dsi);
tegra_dsi_set_dc_clk(dc, dsi);
}
- tegra_dsi_set_control_reg_hs(dsi);
+ tegra_dsi_set_control_reg_hs(dsi, driven_mode);
if (dsi->status.clk_out == DSI_PHYCLK_OUT_DIS ||
dsi->info.enable_hs_clock_on_lp_cmd_mode)
@@ -1845,35 +1909,6 @@ fail:
return (err < 0 ? true : false);
}
-static void tegra_dsi_soft_reset(struct tegra_dc_dsi_data *dsi)
-{
- u32 trigger;
- u32 status;
-
- tegra_dsi_writel(dsi,
- DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE),
- DSI_POWER_CONTROL);
- /* stabilization delay */
- udelay(300);
-
- tegra_dsi_writel(dsi,
- DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE),
- DSI_POWER_CONTROL);
- /* stabilization delay */
- udelay(300);
-
- /* dsi HW does not clear host trigger bit automatically
- * on dsi interface disable if host fifo is empty
- */
- trigger = tegra_dsi_readl(dsi, DSI_TRIGGER);
- status = tegra_dsi_readl(dsi, DSI_STATUS);
- if (trigger & DSI_TRIGGER_HOST_TRIGGER(0x1) &&
- status & DSI_STATUS_IDLE(0x1)) {
- trigger &= ~(DSI_TRIGGER_HOST_TRIGGER(0x1));
- tegra_dsi_writel(dsi, trigger, DSI_TRIGGER);
- }
-}
-
static void tegra_dsi_reset_read_count(struct tegra_dc_dsi_data *dsi)
{
u32 val;
@@ -1892,49 +1927,42 @@ static struct dsi_status *tegra_dsi_save_state_switch_to_host_cmd_mode(
struct tegra_dc *dc,
u8 lp_op)
{
- struct dsi_status *init_status;
+ struct dsi_status *init_status = NULL;
int err;
+ if (dsi->status.init != DSI_MODULE_INIT ||
+ dsi->status.lphs == DSI_LPHS_NOT_INIT) {
+ err = -EPERM;
+ goto fail;
+ }
+
init_status = kzalloc(sizeof(*init_status), GFP_KERNEL);
if (!init_status)
return ERR_PTR(-ENOMEM);
*init_status = dsi->status;
- if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE) {
- if (dsi->status.driven == DSI_DRIVEN_MODE_DC) {
- if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
- tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
- dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_HOST;
- if (dsi->info.hs_cmd_mode_supported) {
- err = tegra_dsi_set_to_hs_mode(dc, dsi);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "Switch to HS host mode failed\n");
- goto fail;
- }
- }
- }
- if (!dsi->info.hs_cmd_mode_supported) {
- 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");
- goto fail;
- }
- }
- } else if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE) {
- if (dsi->status.lp_op != lp_op) {
- 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");
- goto fail;
- }
+ if (dsi->info.hs_cmd_mode_supported) {
+ err = tegra_dsi_set_to_hs_mode(dc, dsi,
+ TEGRA_DSI_DRIVEN_BY_HOST);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "Switch to HS host mode failed\n");
+ goto fail;
}
+
+ goto success;
}
+ if (dsi->status.lp_op != lp_op) {
+ 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");
+ goto fail;
+ }
+ }
+success:
return init_status;
fail:
kfree(init_status);
@@ -1948,6 +1976,7 @@ static struct dsi_status *tegra_dsi_prepare_host_transmission(
{
int err = 0;
struct dsi_status *init_status;
+ bool restart_dc_stream = false;
if (dsi->status.init != DSI_MODULE_INIT ||
dsi->ulpm) {
@@ -1955,12 +1984,13 @@ static struct dsi_status *tegra_dsi_prepare_host_transmission(
goto fail;
}
+ if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE) {
+ restart_dc_stream = true;
+ tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
+ }
+
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");
@@ -1987,6 +2017,9 @@ static struct dsi_status *tegra_dsi_prepare_host_transmission(
goto fail;
}
+ if (restart_dc_stream)
+ init_status->dc_stream = DSI_DC_STREAM_ENABLE;
+
return init_status;
fail:
return ERR_PTR(err);
@@ -1996,50 +2029,30 @@ static int tegra_dsi_restore_state(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi,
struct dsi_status *init_status)
{
- bool switch_back_to_dc_mode = false;
- bool switch_back_to_hs_mode = false;
- bool restart_dc_stream;
int err = 0;
- switch_back_to_dc_mode = (dsi->status.driven ==
- DSI_DRIVEN_MODE_HOST &&
- init_status->driven ==
- DSI_DRIVEN_MODE_DC);
- switch_back_to_hs_mode = (dsi->status.lphs ==
- DSI_LPHS_IN_LP_MODE &&
- init_status->lphs ==
- DSI_LPHS_IN_HS_MODE);
- restart_dc_stream = (dsi->status.dc_stream ==
- DSI_DC_STREAM_DISABLE &&
- init_status->dc_stream ==
- DSI_DC_STREAM_ENABLE);
-
- if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE &&
- init_status->lphs == DSI_LPHS_IN_LP_MODE) {
- if (dsi->status.lp_op != init_status->lp_op) {
- err =
- tegra_dsi_set_to_lp_mode(dc, dsi, init_status->lp_op);
- if (err < 0) {
- dev_err(&dc->ndev->dev,
- "Failed to config LP mode\n");
- goto fail;
- }
+ if (init_status->lphs == DSI_LPHS_IN_LP_MODE) {
+ err = tegra_dsi_set_to_lp_mode(dc, dsi, init_status->lp_op);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev,
+ "Failed to config LP mode\n");
+ goto fail;
}
goto success;
}
- if (switch_back_to_dc_mode)
- dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC;
- if (switch_back_to_dc_mode || switch_back_to_hs_mode) {
- err = tegra_dsi_set_to_hs_mode(dc, dsi);
+ if (init_status->lphs == DSI_LPHS_IN_HS_MODE) {
+ u8 driven = (init_status->driven == DSI_DRIVEN_MODE_DC) ?
+ TEGRA_DSI_DRIVEN_BY_DC : TEGRA_DSI_DRIVEN_BY_HOST;
+ err = tegra_dsi_set_to_hs_mode(dc, dsi, driven);
if (err < 0) {
dev_err(&dc->ndev->dev, "Failed to config HS mode\n");
goto fail;
}
}
- if (restart_dc_stream)
- tegra_dsi_start_dc_stream(dc, dsi);
+ if (init_status->dc_stream == DSI_DC_STREAM_ENABLE)
+ tegra_dsi_start_dc_stream(dc, dsi);
success:
fail:
kfree(init_status);
@@ -2081,7 +2094,6 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
u8 *pdata, u8 data_id, u16 data_len)
{
u8 virtual_channel;
- u8 *pval;
u32 val;
int err;
@@ -2104,10 +2116,9 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
pdata += 4;
} else {
val = 0;
- pval = (u8 *) &val;
- do
- *pval++ = *pdata++;
- while (--data_len);
+ memcpy(&val, pdata, data_len);
+ pdata += data_len;
+ data_len = 0;
}
tegra_dsi_writel(dsi, val, DSI_WR_DATA);
}
@@ -2120,6 +2131,49 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
return err;
}
+static void tegra_dc_dsi_hold_host(struct tegra_dc *dc)
+{
+ struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) {
+ spin_lock(&dsi->host_ref_lock);
+ dsi->host_ref++;
+ spin_unlock(&dsi->host_ref_lock);
+ tegra_dsi_host_resume(dc);
+
+ /*
+ * Take an extra refrence to count for the clk_disable in
+ * tegra_dc_release_host.
+ */
+ clk_enable(dc->clk);
+ }
+}
+
+static void tegra_dc_dsi_release_host(struct tegra_dc *dc)
+{
+ struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+ if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE) {
+ clk_disable(dc->clk);
+ spin_lock(&dsi->host_ref_lock);
+ dsi->host_ref--;
+
+ if (!dsi->host_ref &&
+ (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE))
+ schedule_delayed_work(&dsi->idle_work, dsi->idle_delay);
+
+ spin_unlock(&dsi->host_ref_lock);
+ }
+}
+
+static void tegra_dc_dsi_idle_work(struct work_struct *work)
+{
+ struct tegra_dc_dsi_data *dsi = container_of(
+ to_delayed_work(work), struct tegra_dc_dsi_data, idle_work);
+
+ if (dsi->dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
+ tegra_dsi_host_suspend(dsi->dc);
+}
+
int tegra_dsi_write_data(struct tegra_dc *dc,
struct tegra_dc_dsi_data *dsi,
u8 *pdata, u8 data_id, u16 data_len)
@@ -2143,6 +2197,7 @@ fail:
if (err < 0)
dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
tegra_dc_io_end(dc);
+
return err;
}
EXPORT_SYMBOL(tegra_dsi_write_data);
@@ -2174,7 +2229,7 @@ static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc,
return err;
}
-static u8 get_8bit_ecc(u32 header)
+static u8 tegra_dsi_ecc(u32 header)
{
char ecc_parity[24] = {
0x07, 0x0b, 0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19,
@@ -2191,75 +2246,158 @@ static u8 get_8bit_ecc(u32 header)
return ecc_byte;
}
-/* This function is written to send DCS short write (1 parameter) only.
- * This means the cmd will contain only 1 byte of index and 1 byte of value.
- * The data type ID is fixed at 0x15 and the ECC is calculated based on the
- * data in pdata.
- * The command will be sent by hardware every frame.
- * pdata should contain both the index + value for each cmd.
- * data_len will be the total number of bytes in pdata.
- */
-int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len)
+static u16 tegra_dsi_cs(char *pdata, u16 data_len)
{
- u8 ecc8bits = 0, data_len_orig = 0;
- u32 val = 0, pkthdr = 0;
- int err = 0, count = 0;
- struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
+ u16 byte_cnt;
+ u8 bit_cnt;
+ char curr_byte;
+ u16 crc = 0xFFFF;
+ u16 poly = 0x8408;
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
- tegra_dc_host_resume(dc);
+ if (data_len > 0) {
+ for (byte_cnt = 0; byte_cnt < data_len; byte_cnt++) {
+ curr_byte = pdata[byte_cnt];
+ for (bit_cnt = 0; bit_cnt < 8; bit_cnt++) {
+ if (((crc & 0x0001 ) ^
+ (curr_byte & 0x0001)) > 0)
+ crc = ((crc >> 1) & 0x7FFF) ^ poly;
+ else
+ crc = (crc >> 1) & 0x7FFF;
- data_len_orig = data_len;
- if (pdata != NULL) {
- while (data_len) {
- if (data_len >= 2) {
- pkthdr = (CMD_SHORTW |
- (((u16 *)pdata)[0]) << 8 | 0x00 << 24);
- ecc8bits = get_8bit_ecc(pkthdr);
- val = (pkthdr | (ecc8bits << 24));
- data_len -= 2;
- pdata += 2;
- count++;
+ curr_byte = (curr_byte >> 1 ) & 0x7F;
}
- switch (count) {
- case 1:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0);
- break;
- case 2:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_1);
- break;
- case 3:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_2);
- break;
- case 4:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_3);
- break;
- case 5:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_4);
- break;
- case 6:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_5);
- break;
- case 7:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_6);
- break;
- case 8:
- tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_7);
- break;
- default:
- err = 1;
- break;
+ }
+ }
+ return crc;
+}
+
+static int tegra_dsi_dcs_pkt_seq_ctrl_init(struct tegra_dc_dsi_data *dsi,
+ struct tegra_dsi_cmd *cmd)
+{
+ u8 virtual_channel;
+ u32 val;
+ u16 data_len = cmd->sp_len_dly.data_len;
+ u8 seq_ctrl_reg = 0;
+
+ virtual_channel = dsi->info.virtual_channel <<
+ DSI_VIR_CHANNEL_BIT_POSITION;
+
+ val = (virtual_channel | cmd->data_id) << 0 |
+ data_len << 8;
+
+ val |= tegra_dsi_ecc(val) << 24;
+
+ tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0 + seq_ctrl_reg++);
+
+ /* if pdata != NULL, pkt type is long pkt */
+ if (cmd->pdata != NULL) {
+ u8 *pdata;
+ u8 *pdata_mem;
+ /* allocate memory for pdata + 2 bytes checksum */
+ pdata_mem = kzalloc(sizeof(u8) * data_len + 2, GFP_KERNEL);
+ if (!pdata_mem) {
+ dev_err(&dsi->dc->ndev->dev, "dsi: memory err\n");
+ tegra_dsi_soft_reset(dsi);
+ return -ENOMEM;
+ }
+
+ memcpy(pdata_mem, cmd->pdata, data_len);
+ pdata = pdata_mem;
+ *((u16 *)(pdata + data_len)) = tegra_dsi_cs(pdata, data_len);
+
+ /* data_len = length of pdata + 2 byte checksum */
+ data_len += 2;
+
+ while (data_len) {
+ if (data_len >= 4) {
+ val = ((u32 *) pdata)[0];
+ data_len -= 4;
+ pdata += 4;
+ } else {
+ val = 0;
+ memcpy(&val, pdata, data_len);
+ pdata += data_len;
+ data_len = 0;
}
+ tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0 +
+ seq_ctrl_reg++);
}
+ kfree(pdata_mem);
}
- val = DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(data_len_orig * 2)
- | DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(1);
+ return 0;
+}
+
+int tegra_dsi_start_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi,
+ struct tegra_dsi_cmd *cmd)
+{
+#define PKT_HEADER_LEN_BYTE 4
+#define CHECKSUM_LEN_BYTE 2
+
+ int err = 0;
+ u32 val;
+ u16 tot_pkt_len = PKT_HEADER_LEN_BYTE;
+ struct tegra_dc *dc = dsi->dc;
+
+ if (cmd->cmd_type != TEGRA_DSI_PACKET_CMD)
+ return -EINVAL;
+
+ mutex_lock(&dsi->lock);
+ tegra_dc_dsi_hold_host(dc);
+
+ tegra_dc_io_start(dc);
+
+
+ err = tegra_dsi_dcs_pkt_seq_ctrl_init(dsi, cmd);
+ if (err < 0) {
+ dev_err(&dsi->dc->ndev->dev,
+ "dsi: dcs pkt seq ctrl init failed\n");
+ goto fail;
+ }
+
+ if (cmd->pdata) {
+ u16 data_len = cmd->sp_len_dly.data_len;
+ tot_pkt_len += data_len + CHECKSUM_LEN_BYTE;
+ }
+
+ val = DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(tot_pkt_len) |
+ DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(
+ TEGRA_DSI_ENABLE);
tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL);
+fail:
+ tegra_dc_io_end(dc);
+ tegra_dc_dsi_release_host(dc);
+ mutex_unlock(&dsi->lock);
return err;
+
+#undef PKT_HEADER_LEN_BYTE
+#undef CHECKSUM_LEN_BYTE
}
-EXPORT_SYMBOL(tegra_dsi_send_panel_short_cmd);
+EXPORT_SYMBOL(tegra_dsi_start_host_cmd_v_blank_dcs);
+
+void tegra_dsi_stop_host_cmd_v_blank_dcs(struct tegra_dc_dsi_data * dsi)
+{
+ struct tegra_dc *dc = dsi->dc;
+ u32 cnt;
+
+ mutex_lock(&dsi->lock);
+ tegra_dc_dsi_hold_host(dc);
+
+ tegra_dc_io_start(dc);
+
+ tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_INIT_SEQ_CONTROL);
+
+ /* clear seq data registers */
+ for (cnt = 0; cnt < 8; cnt++)
+ tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + cnt);
+
+ tegra_dc_io_end(dc);
+
+ tegra_dc_dsi_release_host(dc);
+ mutex_unlock(&dsi->lock);
+}
+EXPORT_SYMBOL(tegra_dsi_stop_host_cmd_v_blank_dcs);
static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi)
{
@@ -2429,6 +2567,7 @@ int tegra_dsi_read_data(struct tegra_dc *dc,
int err = 0;
struct dsi_status *init_status;
+ mutex_lock(&dsi->lock);
tegra_dc_io_start(dc);
init_status = tegra_dsi_prepare_host_transmission(
@@ -2487,6 +2626,7 @@ fail:
if (err < 0)
dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
tegra_dc_io_end(dc);
+ mutex_unlock(&dsi->lock);
return err;
}
EXPORT_SYMBOL(tegra_dsi_read_data);
@@ -2625,7 +2765,8 @@ static void tegra_dsi_send_dc_frames(struct tegra_dc *dc,
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);
+ err = tegra_dsi_set_to_hs_mode(dc, dsi,
+ TEGRA_DSI_DRIVEN_BY_DC);
if (err < 0) {
dev_err(&dc->ndev->dev,
"Switch to HS host mode failed\n");
@@ -2668,11 +2809,10 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
int err;
u32 val;
- tegra_dc_io_start(dc);
mutex_lock(&dsi->lock);
+ tegra_dc_dsi_hold_host(dc);
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
- tegra_dc_host_resume(dc);
+ tegra_dc_io_start(dc);
/* Stop DC stream before configuring DSI registers
* to avoid visible glitches on panel during transition
* from bootloader to kernel driver
@@ -2771,7 +2911,8 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
goto fail;
}
- err = tegra_dsi_set_to_hs_mode(dc, dsi);
+ err = tegra_dsi_set_to_hs_mode(dc, dsi,
+ TEGRA_DSI_DRIVEN_BY_DC);
if (err < 0) {
dev_err(&dc->ndev->dev,
"dsi: not able to set to hs mode\n");
@@ -2784,8 +2925,9 @@ static void tegra_dc_dsi_enable(struct tegra_dc *dc)
if (dsi->status.driven == DSI_DRIVEN_MODE_DC)
tegra_dsi_start_dc_stream(dc, dsi);
fail:
- mutex_unlock(&dsi->lock);
tegra_dc_io_end(dc);
+ tegra_dc_dsi_release_host(dc);
+ mutex_unlock(&dsi->lock);
}
static void _tegra_dc_dsi_init(struct tegra_dc *dc)
@@ -3179,8 +3321,7 @@ fail:
return err;
}
-
-int tegra_dsi_host_suspend(struct tegra_dc *dc)
+static int tegra_dsi_host_suspend(struct tegra_dc *dc)
{
int err = 0;
struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
@@ -3188,6 +3329,10 @@ int tegra_dsi_host_suspend(struct tegra_dc *dc)
if (dsi->host_suspended)
return 0;
+ BUG_ON(!tegra_is_clk_enabled(dc->clk));
+ tegra_dc_io_start(dc);
+ dsi->host_suspended = true;
+
tegra_dsi_stop_dc_stream(dc, dsi);
err = tegra_dsi_deep_sleep(dc, dsi, dsi->info.suspend_aggr);
@@ -3195,21 +3340,26 @@ int tegra_dsi_host_suspend(struct tegra_dc *dc)
dev_err(&dc->ndev->dev,
"DSI failed to enter deep sleep\n");
- dsi->host_suspended = true;
+ tegra_dc_clk_disable(dc);
+ tegra_dc_io_end(dc);
return err;
}
-
-int tegra_dsi_host_resume(struct tegra_dc *dc)
+static 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)
+ mutex_lock(&dsi->host_resume_lock);
+ cancel_delayed_work_sync(&dsi->idle_work);
+ if (!dsi->host_suspended) {
+ mutex_unlock(&dsi->host_resume_lock);
return 0;
+ }
+ tegra_dc_clk_enable(dc);
switch (dsi->info.suspend_aggr) {
case DSI_HOST_SUSPEND_LV0:
tegra_dsi_clk_enable(dsi);
@@ -3254,9 +3404,11 @@ int tegra_dsi_host_resume(struct tegra_dc *dc)
"is not supported.\n");
}
+ tegra_dsi_start_dc_stream(dc, dsi);
+
dsi->enabled = true;
dsi->host_suspended = false;
- tegra_dsi_start_dc_stream(dc, dsi);
+ mutex_unlock(&dsi->host_resume_lock);
fail:
return err;
}
@@ -3298,7 +3450,6 @@ static void tegra_dc_dsi_disable(struct tegra_dc *dc)
}
}
}
-
fail:
mutex_unlock(&dsi->lock);
tegra_dc_io_end(dc);
@@ -3350,6 +3501,8 @@ struct tegra_dc_out_ops tegra_dc_dsi_ops = {
.destroy = tegra_dc_dsi_destroy,
.enable = tegra_dc_dsi_enable,
.disable = tegra_dc_dsi_disable,
+ .hold = tegra_dc_dsi_hold_host,
+ .release = tegra_dc_dsi_release_host,
#ifdef CONFIG_PM
.suspend = tegra_dc_dsi_suspend,
.resume = tegra_dc_dsi_resume,
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
index f9c76f8f0d0d..88273e26c51c 100644
--- a/drivers/video/tegra/dc/ext/dev.c
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -56,6 +56,7 @@ struct tegra_dc_ext_flip_data {
struct tegra_dc_ext *ext;
struct work_struct work;
struct tegra_dc_ext_flip_win win[DC_N_WINDOWS];
+ struct list_head timestamp_node;
};
int tegra_dc_ext_get_num_outputs(void)
@@ -207,6 +208,7 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
{
int err = 0;
struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
+ s64 timestamp_ns;
if (flip_win->handle[TEGRA_DC_Y] == NULL) {
win->flags = 0;
@@ -270,9 +272,56 @@ static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
msecs_to_jiffies(500), NULL);
}
+#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
+ timestamp_ns = timespec_to_ns(&flip_win->attr.timestamp);
+
+ if (timestamp_ns) {
+ /* XXX: Should timestamping be overridden by "no_vsync" flag */
+ tegra_dc_config_frame_end_intr(win->dc, true);
+ trace_printk("%s:Before timestamp wait\n", win->dc->ndev->name);
+ err = wait_event_interruptible(win->dc->timestamp_wq,
+ tegra_dc_is_within_n_vsync(win->dc, timestamp_ns));
+ trace_printk("%s:After timestamp wait\n", win->dc->ndev->name);
+ tegra_dc_config_frame_end_intr(win->dc, false);
+ }
+#endif
+ return err;
+}
+
+static void (*flip_callback)(void);
+static spinlock_t flip_callback_lock;
+static bool init_tegra_dc_flip_callback_called;
+
+static int __init init_tegra_dc_flip_callback(void)
+{
+ spin_lock_init(&flip_callback_lock);
+ init_tegra_dc_flip_callback_called = true;
+ return 0;
+}
+
+pure_initcall(init_tegra_dc_flip_callback);
+
+int tegra_dc_set_flip_callback(void (*callback)(void))
+{
+ WARN_ON(!init_tegra_dc_flip_callback_called);
+
+ spin_lock(&flip_callback_lock);
+ flip_callback = callback;
+ spin_unlock(&flip_callback_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_set_flip_callback);
+
+int tegra_dc_unset_flip_callback()
+{
+ spin_lock(&flip_callback_lock);
+ flip_callback = NULL;
+ spin_unlock(&flip_callback_lock);
return 0;
}
+EXPORT_SYMBOL(tegra_dc_unset_flip_callback);
static void tegra_dc_ext_flip_worker(struct work_struct *work)
{
@@ -288,9 +337,11 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
for (i = 0; i < DC_N_WINDOWS; i++) {
struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
- int index = flip_win->attr.index;
+ int j = 0, index = flip_win->attr.index;
struct tegra_dc_win *win;
struct tegra_dc_ext_win *ext_win;
+ struct tegra_dc_ext_flip_data *temp = NULL;
+ s64 head_timestamp = 0;
if (index < 0)
continue;
@@ -302,6 +353,31 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
(flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR))
skip_flip = true;
+ mutex_lock(&ext_win->queue_lock);
+ list_for_each_entry(temp, &ext_win->timestamp_queue,
+ timestamp_node) {
+ if (j == 0) {
+ if (unlikely(temp != data))
+ dev_err(&win->dc->ndev->dev,
+ "work queue did NOT dequeue head!!!");
+ else
+ head_timestamp =
+ timespec_to_ns(&flip_win->attr.timestamp);
+ } else {
+ s64 timestamp =
+ timespec_to_ns(&temp->win[i].attr.timestamp);
+
+ skip_flip = !tegra_dc_does_vsync_separate(ext->dc,
+ timestamp, head_timestamp);
+ /* Look ahead only one flip */
+ break;
+ }
+ j++;
+ }
+ if (!list_empty(&ext_win->timestamp_queue))
+ list_del(&data->timestamp_node);
+ mutex_unlock(&ext_win->queue_lock);
+
if (win->flags & TEGRA_WIN_FLAG_ENABLED) {
int j;
for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
@@ -327,17 +403,23 @@ static void tegra_dc_ext_flip_worker(struct work_struct *work)
tegra_dc_update_windows(wins, nr_win);
/* TODO: implement swapinterval here */
tegra_dc_sync_windows(wins, nr_win);
- }
+ if (!tegra_dc_has_multiple_dc()) {
+ spin_lock(&flip_callback_lock);
+ if (flip_callback)
+ flip_callback();
+ spin_unlock(&flip_callback_lock);
+ }
- for (i = 0; i < DC_N_WINDOWS; i++) {
- struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
- int index = flip_win->attr.index;
+ for (i = 0; i < DC_N_WINDOWS; i++) {
+ struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
+ int index = flip_win->attr.index;
- if (index < 0)
- continue;
+ if (index < 0)
+ continue;
- tegra_dc_incr_syncpt_min(ext->dc, index,
- flip_win->syncpt_max);
+ tegra_dc_incr_syncpt_min(ext->dc, index,
+ flip_win->syncpt_max);
+ }
}
/* unpin and deref previous front buffers */
@@ -449,6 +531,7 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
struct tegra_dc_ext_flip_data *data;
int work_index = -1;
int i, ret = 0;
+ bool has_timestamp = false;
#ifdef CONFIG_ANDROID
int index_check[DC_N_WINDOWS] = {0, };
@@ -489,6 +572,8 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
int index = args->win[i].index;
memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
+ if (timespec_to_ns(&flip_win->attr.timestamp))
+ has_timestamp = true;
if (index < 0)
continue;
@@ -563,6 +648,11 @@ static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
ret = -EINVAL;
goto unlock;
}
+ if (has_timestamp) {
+ mutex_lock(&ext->win[work_index].queue_lock);
+ list_add_tail(&data->timestamp_node, &ext->win[work_index].timestamp_queue);
+ mutex_unlock(&ext->win[work_index].queue_lock);
+ }
queue_work(ext->win[work_index].flip_wq, &data->work);
unlock_windows_for_flip(user, args);
@@ -903,6 +993,8 @@ static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
}
mutex_init(&win->lock);
+ mutex_init(&win->queue_lock);
+ INIT_LIST_HEAD(&win->timestamp_queue);
}
return 0;
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 f68c7d5c93c2..ef7361d1d933 100644
--- a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -58,6 +58,10 @@ struct tegra_dc_ext_win {
struct workqueue_struct *flip_wq;
atomic_t nr_pending_flips;
+
+ struct mutex queue_lock;
+
+ struct list_head timestamp_queue;
};
struct tegra_dc_ext {
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 79478ea48f83..55d9163d4faf 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -1370,18 +1370,31 @@ bool tegra_dc_hdmi_detect_test(struct tegra_dc *dc, unsigned char *edid_ptr)
err = tegra_edid_get_monspecs_test(hdmi->edid, &specs, edid_ptr);
if (err < 0) {
- dev_err(&dc->ndev->dev, "error reading edid\n");
- goto fail;
- }
+ /* Check if there's a hard-wired mode, if so, enable it */
+ if (dc->out->n_modes)
+ tegra_dc_enable(dc);
+ else {
+ dev_err(&dc->ndev->dev, "error reading edid\n");
+ goto fail;
+ }
+#ifdef CONFIG_SWITCH
+ hdmi->hpd_switch.state = 0;
+ switch_set_state(&hdmi->hpd_switch, 1);
+#endif
+ dev_info(&dc->ndev->dev, "display detected\n");
- err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld);
- if (err < 0) {
- dev_err(&dc->ndev->dev, "error populating eld\n");
- goto fail;
- }
- hdmi->eld_retrieved = true;
+ dc->connected = true;
+ tegra_dc_ext_process_hotplug(dc->ndev->id);
+ } else {
+ err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev, "error populating eld\n");
+ goto fail;
+ }
+ hdmi->eld_retrieved = true;
- tegra_dc_hdmi_detect_config(dc, &specs);
+ tegra_dc_hdmi_detect_config(dc, &specs);
+ }
return true;
@@ -1406,18 +1419,30 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc)
err = tegra_edid_get_monspecs(hdmi->edid, &specs);
if (err < 0) {
- dev_err(&dc->ndev->dev, "error reading edid\n");
- goto fail;
- }
+ if (dc->out->n_modes)
+ tegra_dc_enable(dc);
+ else {
+ dev_err(&dc->ndev->dev, "error reading edid\n");
+ goto fail;
+ }
+#ifdef CONFIG_SWITCH
+ hdmi->hpd_switch.state = 0;
+ switch_set_state(&hdmi->hpd_switch, 1);
+#endif
+ dev_info(&dc->ndev->dev, "display detected\n");
- err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld);
- if (err < 0) {
- dev_err(&dc->ndev->dev, "error populating eld\n");
- goto fail;
- }
- hdmi->eld_retrieved = true;
+ dc->connected = true;
+ tegra_dc_ext_process_hotplug(dc->ndev->id);
+ } else {
+ err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld);
+ if (err < 0) {
+ dev_err(&dc->ndev->dev, "error populating eld\n");
+ goto fail;
+ }
+ hdmi->eld_retrieved = true;
- tegra_dc_hdmi_detect_config(dc, &specs);
+ tegra_dc_hdmi_detect_config(dc, &specs);
+ }
return true;
diff --git a/drivers/video/tegra/dc/mode.c b/drivers/video/tegra/dc/mode.c
index 49cc5f5abd53..3a95f2e7ab0e 100644
--- a/drivers/video/tegra/dc/mode.c
+++ b/drivers/video/tegra/dc/mode.c
@@ -137,6 +137,17 @@ static bool check_ref_to_sync(struct tegra_dc_mode *mode)
return true;
}
+static s64 calc_frametime_ns(const struct tegra_dc_mode *m)
+{
+ long h_total, v_total;
+ 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;
+ return (!m->pclk) ? 0 : (s64)(div_s64(((s64)h_total * v_total *
+ 1000000000ULL), m->pclk));
+}
+
/* return in 1000ths of a Hertz */
int tegra_dc_calc_refresh(const struct tegra_dc_mode *m)
{
@@ -247,11 +258,25 @@ int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
return 0;
}
+static int panel_sync_rate;
+
+int tegra_dc_get_panel_sync_rate(void)
+{
+ return panel_sync_rate;
+}
+EXPORT_SYMBOL(tegra_dc_get_panel_sync_rate);
+
int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
{
memcpy(&dc->mode, mode, sizeof(dc->mode));
+ if (dc->out->type == TEGRA_DC_OUT_RGB)
+ panel_sync_rate = tegra_dc_calc_refresh(mode);
+ else if (dc->out->type == TEGRA_DC_OUT_DSI)
+ panel_sync_rate = dc->out->dsi->rated_refresh_rate * 1000;
+
print_mode(dc, mode, __func__);
+ dc->frametime_ns = calc_frametime_ns(mode);
return 0;
}
diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c
index e3058b596f69..6e76ee0f1702 100644
--- a/drivers/video/tegra/dc/nvsd.c
+++ b/drivers/video/tegra/dc/nvsd.c
@@ -809,9 +809,12 @@ static ssize_t nvsd_settings_store(struct kobject *kobj,
mutex_unlock(&dc->lock);
return -ENODEV;
}
- mutex_unlock(&dc->lock);
+ tegra_dc_hold_dc_out(dc);
nvsd_init(dc, sd_settings);
+ tegra_dc_release_dc_out(dc);
+
+ mutex_unlock(&dc->lock);
/* Update backlight state IFF we're disabling! */
if (!sd_settings->enable && sd_settings->bl_device) {
diff --git a/drivers/video/tegra/dc/window.c b/drivers/video/tegra/dc/window.c
index 5161dd4f7003..cd91fab428ed 100644
--- a/drivers/video/tegra/dc/window.c
+++ b/drivers/video/tegra/dc/window.c
@@ -24,6 +24,7 @@
#include "dc_priv.h"
static int no_vsync;
+static atomic_t frame_end_ref = ATOMIC_INIT(0);
module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
@@ -40,6 +41,17 @@ static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
return true;
}
+int tegra_dc_config_frame_end_intr(struct tegra_dc *dc, bool enable)
+{
+ tegra_dc_writel(dc, FRAME_END_INT, DC_CMD_INT_STATUS);
+ if (enable) {
+ atomic_inc(&frame_end_ref);
+ tegra_dc_unmask_interrupt(dc, FRAME_END_INT);
+ } else if (!atomic_dec_return(&frame_end_ref))
+ tegra_dc_mask_interrupt(dc, FRAME_END_INT);
+ return 0;
+}
+
static int get_topmost_window(u32 *depths, unsigned long *wins)
{
int idx, best = -1;
@@ -219,8 +231,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
return -EFAULT;
}
- if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_LP_MODE)
- tegra_dc_host_resume(dc);
+ tegra_dc_hold_dc_out(dc);
if (no_vsync)
tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE,
@@ -407,8 +418,9 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
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);
+ tegra_dc_mask_interrupt(dc, V_BLANK_INT | ALL_UF_INT);
+ if (!atomic_read(&frame_end_ref))
+ tegra_dc_mask_interrupt(dc, FRAME_END_INT);
}
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
@@ -424,6 +436,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
trace_printk("%s:update_mask=%#lx\n", dc->ndev->name, update_mask);
+ tegra_dc_release_dc_out(dc);
mutex_unlock(&dc->lock);
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
mutex_unlock(&dc->one_shot_lock);
@@ -456,7 +469,8 @@ void tegra_dc_trigger_windows(struct tegra_dc *dc)
}
if (!dirty) {
- if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE))
+ if (!(dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
+ && !atomic_read(&frame_end_ref))
tegra_dc_mask_interrupt(dc, FRAME_END_INT);
}
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index cb7525e049e9..59c162bb3b4c 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -96,6 +96,7 @@ static int tegra_fb_set_par(struct fb_info *info)
{
struct tegra_fb_info *tegra_fb = info->par;
struct fb_var_screeninfo *var = &info->var;
+ struct tegra_dc *dc = tegra_fb->win->dc;
if (var->bits_per_pixel) {
/* we only support RGB ordering for now */
@@ -124,10 +125,13 @@ static int tegra_fb_set_par(struct fb_info *info)
default:
return -EINVAL;
}
- info->fix.line_length = var->xres * var->bits_per_pixel / 8;
- /* Pad the stride to 16-byte boundary. */
- info->fix.line_length = round_up(info->fix.line_length,
+ /* if line_length unset, then pad the stride */
+ if (!info->fix.line_length) {
+ info->fix.line_length = var->xres * var->bits_per_pixel
+ / 8;
+ info->fix.line_length = round_up(info->fix.line_length,
TEGRA_LINEAR_PITCH_ALIGNMENT);
+ }
tegra_fb->win->stride = info->fix.line_length;
tegra_fb->win->stride_uv = 0;
tegra_fb->win->phys_addr_u = 0;
@@ -136,17 +140,30 @@ static int tegra_fb_set_par(struct fb_info *info)
if (var->pixclock) {
bool stereo;
+ unsigned old_len = 0;
struct fb_videomode m;
+ struct fb_videomode *old_mode = NULL;
fb_var_to_videomode(&m, var);
+ /* Load framebuffer info with new mode details*/
+ old_mode = info->mode;
+ old_len = info->fix.line_length;
+
info->mode = (struct fb_videomode *)
fb_find_nearest_mode(&m, &info->modelist);
if (!info->mode) {
dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n");
+ info->mode = old_mode;
return -EINVAL;
}
+ /* Update fix line_length and window stride as per new mode */
+ info->fix.line_length = var->xres * var->bits_per_pixel / 8;
+ info->fix.line_length = round_up(info->fix.line_length,
+ TEGRA_LINEAR_PITCH_ALIGNMENT);
+ tegra_fb->win->stride = info->fix.line_length;
+
/*
* only enable stereo if the mode supports it and
* client requests it
@@ -157,10 +174,22 @@ 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);
+
+ /* Configure DC with new mode */
+ if (tegra_dc_set_fb_mode(dc, info->mode, stereo)) {
+ /* Error while configuring DC, fallback to old mode */
+ dev_warn(&tegra_fb->ndev->dev, "can't configure dc with mode %ux%u\n",
+ info->mode->xres, info->mode->yres);
+ info->mode = old_mode;
+ info->fix.line_length = old_len;
+ tegra_fb->win->stride = old_len;
+ return -EINVAL;
+ }
+
+ /* Reflect mode chnage on DC HW */
+ if (dc->enabled)
+ tegra_dc_disable(dc);
+ tegra_dc_enable(dc);
tegra_fb->win->w.full = dfixed_const(info->mode->xres);
tegra_fb->win->h.full = dfixed_const(info->mode->yres);
@@ -326,8 +355,10 @@ static void tegra_fb_imageblit(struct fb_info *info,
static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
+ struct tegra_fb_info *tegra_fb = (struct tegra_fb_info *)info->par;
struct tegra_fb_modedb modedb;
struct fb_modelist *modelist;
+ struct fb_vblank vblank = {};
int i;
switch (cmd) {
@@ -370,6 +401,17 @@ static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long
return -EFAULT;
break;
+ case FBIOGET_VBLANK:
+ tegra_dc_get_fbvblank(tegra_fb->win->dc, &vblank);
+
+ if (copy_to_user(
+ (void __user *)arg, &vblank, sizeof(vblank)))
+ return -EFAULT;
+ break;
+
+ case FBIO_WAITFORVSYNC:
+ return tegra_dc_wait_for_vsync(tegra_fb->win->dc);
+
default:
return -ENOTTY;
}
@@ -607,8 +649,10 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
tegra_fb->valid = true;
}
+ info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8;
+
stride = tegra_dc_get_stride(dc, 0);
- if (!stride) /* default to pad the stride to 16-byte boundary. */
+ if (!stride) /* default to pad the stride */
stride = round_up(info->fix.line_length,
TEGRA_LINEAR_PITCH_ALIGNMENT);
@@ -625,7 +669,6 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->fix.accel = FB_ACCEL_NONE;
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;
info->fix.line_length = stride;
info->var.xres = fb_data->xres;
@@ -683,6 +726,7 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
if (dc->mode.pclk > 1000) {
struct tegra_dc_mode *mode = &dc->mode;
+ struct fb_videomode vmode;
if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
@@ -694,6 +738,10 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->var.lower_margin = mode->v_front_porch;
info->var.hsync_len = mode->h_sync_width;
info->var.vsync_len = mode->v_sync_width;
+
+ /* Keep info->var consistent with info->modelist. */
+ fb_var_to_videomode(&vmode, &info->var);
+ fb_add_videomode(&vmode, &info->modelist);
}
return tegra_fb;
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
index 758a5ca4ad94..f22dac288051 100644
--- a/drivers/video/tegra/host/bus.c
+++ b/drivers/video/tegra/host/bus.c
@@ -96,7 +96,7 @@ static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
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));
+ return !strcmp(dev->name, drv->name);
}
static int nvhost_drv_probe(struct device *_dev)
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
index 0137793b39ee..aaa038221971 100644
--- a/drivers/video/tegra/host/bus_client.c
+++ b/drivers/video/tegra/host/bus_client.c
@@ -159,7 +159,8 @@ static int nvhost_channelopen(struct inode *inode, struct file *filp)
}
filp->private_data = priv;
priv->ch = ch;
- nvhost_module_add_client(ch->dev, priv);
+ if(nvhost_module_add_client(ch->dev, priv))
+ goto fail;
if (ch->ctxhandler && ch->ctxhandler->alloc) {
priv->hwctx = ch->ctxhandler->alloc(ch->ctxhandler, ch);
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
index f5d2811f143f..412ce8b65466 100644
--- a/drivers/video/tegra/host/chip_support.h
+++ b/drivers/video/tegra/host/chip_support.h
@@ -125,6 +125,7 @@ struct nvhost_intr_ops {
void (*set_syncpt_threshold)(
struct nvhost_intr *, u32 id, u32 thresh);
void (*enable_syncpt_intr)(struct nvhost_intr *, u32 id);
+ void (*disable_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 *);
diff --git a/drivers/video/tegra/host/gr3d/gr3d.c b/drivers/video/tegra/host/gr3d/gr3d.c
index 715468131d9e..775c77b0e88d 100644
--- a/drivers/video/tegra/host/gr3d/gr3d.c
+++ b/drivers/video/tegra/host/gr3d/gr3d.c
@@ -80,8 +80,10 @@ struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
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))
+ if (IS_ERR_OR_NULL(ctx->restore)) {
+ ctx->restore = NULL;
goto fail;
+ }
if (map_restore) {
ctx->restore_virt = mem_op().mmap(ctx->restore);
diff --git a/drivers/video/tegra/host/gr3d/gr3d.h b/drivers/video/tegra/host/gr3d/gr3d.h
index 3855b237b702..61f708cea95c 100644
--- a/drivers/video/tegra/host/gr3d/gr3d.h
+++ b/drivers/video/tegra/host/gr3d/gr3d.h
@@ -29,6 +29,9 @@
#define AR3D_PSEQ_QUAD_ID 0x545
#define AR3D_DW_MEMORY_OUTPUT_ADDRESS 0x904
#define AR3D_DW_MEMORY_OUTPUT_DATA 0x905
+#define AR3D_FDC_CONTROL_0 0xa00
+#define AR3D_FDC_CONTROL_0_RESET_VAL 0xe00
+#define AR3D_FDC_CONTROL_0_INVALIDATE 1
#define AR3D_GSHIM_WRITE_MASK 0xb00
#define AR3D_GSHIM_READ_SELECT 0xb01
#define AR3D_GLOBAL_MEMORY_OUTPUT_READS 0xe40
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.c b/drivers/video/tegra/host/gr3d/gr3d_t20.c
index b6e3896fe50c..694b00527790 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t20.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.c
@@ -144,7 +144,7 @@ static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
p->save_phys);
}
-static void __init save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
+static void 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);
@@ -162,7 +162,7 @@ static void __init save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
h->syncpt); /* incr 2 */
}
-static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
+static void save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
{
ptr[0] = nvhost_opcode_nonincr(host1x_uclass_indoff_r(), 1);
ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
@@ -170,7 +170,7 @@ static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
ptr[2] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
-static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
+static void save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
u32 data_reg, u32 count)
{
ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
@@ -183,7 +183,7 @@ static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
ptr[4] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
-static void __init save_end_v0(struct host1x_hwctx_handler *h, u32 *ptr)
+static void 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(host1x_uclass_wait_syncpt_base_r(), 1);
@@ -226,7 +226,7 @@ static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
/*** save ***/
-static void __init setup_save_regs(struct save_info *info,
+static void setup_save_regs(struct save_info *info,
const struct hwctx_reginfo *regs,
unsigned int nr_regs)
{
@@ -284,7 +284,7 @@ static void __init setup_save_regs(struct save_info *info,
info->restore_count = restore_count;
}
-static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
+static void setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
{
struct save_info info = {
ptr,
@@ -371,7 +371,7 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
p->save_buf = mem_op().alloc(memmgr, p->save_size * sizeof(u32), 32,
mem_mgr_flag_write_combine);
- if (IS_ERR(p->save_buf)) {
+ if (IS_ERR_OR_NULL(p->save_buf)) {
p->save_buf = NULL;
return NULL;
}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
index c35fea2f3ac2..664708c7fc80 100644
--- a/drivers/video/tegra/host/gr3d/gr3d_t30.c
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -125,6 +125,16 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
NVHOST_OPCODE_NOOP);
+ /* invalidate the FDC to prevent cache-coherency issues across GPUs
+ note that we assume FDC_CONTROL_0 is left in the reset state by all
+ contexts. the invalidate bit will clear itself, so the register
+ should be unchanged after this */
+ nvhost_cdma_push(cdma,
+ nvhost_opcode_imm(AR3D_FDC_CONTROL_0,
+ AR3D_FDC_CONTROL_0_RESET_VAL
+ | AR3D_FDC_CONTROL_0_INVALIDATE),
+ NVHOST_OPCODE_NOOP);
+
/* set register set 0 and 1 register read memory output addresses,
and send their reads to memory */
@@ -132,7 +142,7 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *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),
+ nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_ADDRESS, 1),
ctx->restore_phys + restore_set1_offset * 4);
nvhost_cdma_push(cdma,
@@ -150,7 +160,7 @@ static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
p->save_phys);
}
-static void __init save_begin_v1(struct host1x_hwctx_handler *p, u32 *ptr)
+static void save_begin_v1(struct host1x_hwctx_handler *p, u32 *ptr)
{
ptr[0] = nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_DATA,
RESTORE_BEGIN_SIZE);
@@ -158,7 +168,7 @@ static void __init save_begin_v1(struct host1x_hwctx_handler *p, u32 *ptr)
ptr += RESTORE_BEGIN_SIZE;
}
-static void __init save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
+static void save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
{
ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
AR3D_DW_MEMORY_OUTPUT_DATA, 1);
@@ -172,7 +182,7 @@ static void __init save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
ptr[3] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
-static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
+static void save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
u32 data_reg, u32 count)
{
ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
@@ -189,7 +199,7 @@ static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
ptr[5] = nvhost_opcode_nonincr(host1x_uclass_inddata_r(), count);
}
-static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
+static void save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
{
/* write end of restore buffer */
ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
@@ -224,7 +234,7 @@ static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
-static void __init setup_save_regs(struct save_info *info,
+static void setup_save_regs(struct save_info *info,
const struct hwctx_reginfo *regs,
unsigned int nr_regs)
{
@@ -282,7 +292,7 @@ static void __init setup_save_regs(struct save_info *info,
info->restore_count = restore_count;
}
-static void __init switch_gpu(struct save_info *info,
+static void switch_gpu(struct save_info *info,
unsigned int save_src_set,
u32 save_dest_sets,
u32 restore_dest_sets)
@@ -303,7 +313,7 @@ static void __init switch_gpu(struct save_info *info,
info->restore_count += 1;
}
-static void __init setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
+static void setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
{
struct save_info info = {
ptr,
@@ -399,7 +409,7 @@ struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
p->save_buf = mem_op().alloc(memmgr, p->save_size * 4, 32,
mem_mgr_flag_write_combine);
- if (IS_ERR(p->save_buf)) {
+ if (IS_ERR_OR_NULL(p->save_buf)) {
p->save_buf = NULL;
return NULL;
}
diff --git a/drivers/video/tegra/host/gr3d/scale3d.c b/drivers/video/tegra/host/gr3d/scale3d.c
index 5922b55a836a..49147975a9e4 100644
--- a/drivers/video/tegra/host/gr3d/scale3d.c
+++ b/drivers/video/tegra/host/gr3d/scale3d.c
@@ -1,9 +1,9 @@
/*
- * drivers/video/tegra/host/t20/scale3d.c
+ * drivers/video/tegra/host/gr3d/scale3d.c
*
* Tegra Graphics Host 3D clock scaling
*
- * 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,
@@ -23,12 +23,11 @@
*
* module3d_notify_busy() is called upon submit, module3d_notify_idle() is
* called when all outstanding submits are completed. Idle times are measured
- * over a fixed time period (scale3d.p_period). If the 3d module idle time
- * percentage goes over the limit (set in scale3d.p_idle_max), 3d clocks are
- * scaled down. If the percentage goes under the minimum limit (set in
- * scale3d.p_idle_min), 3d clocks are scaled up. An additional test is made
- * over the time frame given in scale3d.p_fast_response for clocking up
- * quickly in response to load peaks.
+ * over a fixed time period (scale3d.p_estimation_window). If the 3d module
+ * idle time percentage goes over the limit (set in scale3d.p_idle_max), 3d
+ * clocks are scaled down. If the percentage goes under the minimum limit (set
+ * in scale3d.p_idle_min), 3d clocks are scaled up. An additional test is made
+ * for clocking up quickly in response to load peaks.
*
* 3d.emc clock is scaled proportionately to 3d clock, with a quadratic-
* bezier-like factor added to pull 3d.emc rate a bit lower.
@@ -37,10 +36,31 @@
#include <linux/debugfs.h>
#include <linux/types.h>
#include <linux/clk.h>
+#include <linux/slab.h>
#include <mach/clk.h>
#include <mach/hardware.h>
#include "scale3d.h"
#include "dev.h"
+#include <media/tegra_camera.h>
+
+#define GR3D_PRINT_STATS BIT(1)
+#define GR3D_PRINT_BUSY BIT(2)
+#define GR3D_PRINT_IDLE BIT(3)
+#define GR3D_PRINT_HINT BIT(4)
+#define GR3D_PRINT_TARGET BIT(5)
+
+/* time frame for load and hint tracking - when events come in at a larger
+ * interval, this probably indicates the current estimates are stale
+ */
+#define GR3D_TIMEFRAME 1000000 /* 1 sec */
+
+/* the number of frames to use in the running average of load estimates and
+ * throughput hints. Choosing 6 frames targets a window of about 100 msec.
+ * Large flucutuations in frame times require a window that's large enough to
+ * prevent spiky scaling behavior, which in turn exacerbates frame rate
+ * instability.
+ */
+#define GR3D_FRAME_SPAN 6
static int scale3d_is_enabled(void);
static void scale3d_enable(int enable);
@@ -48,54 +68,73 @@ static void scale3d_enable(int enable);
#define POW2(x) ((x) * (x))
/*
+ * 3D clock scaling should be treated differently when camera is on in AP37.
+ * 3D in AP37 requires 1.3V and combining it with MPE reaches to EDP limit.
+ * 3D clock really needs to be set to lower frequency which requires 1.0V.
+ * The same thing applies to 3D EMC clock.
+ */
+#define CAMERA_3D_CLK 300000000
+#define CAMERA_3D_EMC_CLK 437000000
+
+/*
* debugfs parameters to control 3d clock scaling test
*
- * period - time period for clock rate evaluation
- * fast_response - time period for evaluation of 'busy' spikes
- * idle_min - if less than [idle_min] percent idle over [fast_response]
- * microseconds, clock up.
- * idle_max - if over [idle_max] percent idle over [period] microseconds,
- * clock down.
+ * estimation_window - time period for clock rate evaluation
+ * idle_min - if less than [idle_min / 10] percent idle over
+ * [estimation_window] microseconds, clock up.
+ * idle_max - if over [idle_max] percent idle over [estimation_window]
+ * microseconds, clock down.
* max_scale - limits rate changes to no less than (100 - max_scale)% or
* (100 + 2 * max_scale)% of current clock rate
- * verbosity - set above 5 for debug printouts
+ * verbosity - bit flag to control debug printouts:
+ * 1 - stats
+ * 2 - busy
+ * 3 - idle
+ * 4 - hints
+ * 5 - target frequencies
*/
struct scale3d_info_rec {
struct mutex lock; /* lock for timestamps etc */
int enable;
int init;
- ktime_t idle_frame;
- ktime_t fast_frame;
- ktime_t last_idle;
- ktime_t last_short_term_idle;
+ ktime_t last_scale;
int is_idle;
- ktime_t last_tweak;
- ktime_t last_down;
+ ktime_t last_adjust;
int fast_up_count;
int slow_down_count;
int is_scaled;
- int fast_responses;
- unsigned long idle_total;
- unsigned long idle_short_term_total;
- unsigned long max_rate_3d;
long emc_slope;
long emc_offset;
long emc_dip_slope;
long emc_dip_offset;
long emc_xmid;
+ unsigned long max_rate_3d;
unsigned long min_rate_3d;
+ ktime_t last_throughput_hint;
+
struct work_struct work;
struct delayed_work idle_timer;
+
+ ktime_t last_estimation_window;
+ long last_total_idle;
+ long total_idle;
+ ktime_t estimation_window;
+ ktime_t last_notification;
+ long idle_estimate;
+
unsigned int scale;
- unsigned int p_period;
- unsigned int period;
+ unsigned int p_busy_cutoff;
+ unsigned int p_estimation_window;
+ unsigned int p_use_throughput_hint;
+ unsigned int p_throughput_lo_limit;
+ unsigned int p_throughput_lower_limit;
+ unsigned int p_throughput_hi_limit;
+ unsigned int p_scale_step;
unsigned int p_idle_min;
unsigned int idle_min;
unsigned int p_idle_max;
unsigned int idle_max;
- unsigned int p_fast_response;
- unsigned int fast_response;
unsigned int p_adjust;
unsigned int p_scale_emc;
unsigned int p_emc_dip;
@@ -103,13 +142,15 @@ struct scale3d_info_rec {
struct clk *clk_3d;
struct clk *clk_3d2;
struct clk *clk_3d_emc;
+ int *freqlist;
+ int freq_count;
};
static struct scale3d_info_rec scale3d;
-static void scale3d_clocks(unsigned long percent)
+static void scale_to_freq(unsigned long hz)
{
- unsigned long hz, curr;
+ unsigned long curr;
if (!tegra_is_clk_enabled(scale3d.clk_3d))
return;
@@ -119,7 +160,8 @@ static void scale3d_clocks(unsigned long percent)
return;
curr = clk_get_rate(scale3d.clk_3d);
- hz = percent * (curr / 100);
+ if (hz == curr)
+ return;
if (!(hz >= scale3d.max_rate_3d && curr == scale3d.max_rate_3d)) {
if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
@@ -139,6 +181,16 @@ static void scale3d_clocks(unsigned long percent)
}
}
+static void scale3d_clocks(unsigned long percent)
+{
+ unsigned long hz, curr;
+
+ curr = clk_get_rate(scale3d.clk_3d);
+ hz = percent * (curr / 100);
+
+ scale_to_freq(hz);
+}
+
static void scale3d_clocks_handler(struct work_struct *work)
{
unsigned int scale;
@@ -164,12 +216,26 @@ void nvhost_scale3d_suspend(struct nvhost_device *dev)
static void reset_3d_clocks(void)
{
if (clk_get_rate(scale3d.clk_3d) != scale3d.max_rate_3d) {
- clk_set_rate(scale3d.clk_3d, scale3d.max_rate_3d);
- if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
- clk_set_rate(scale3d.clk_3d2, scale3d.max_rate_3d);
- if (scale3d.p_scale_emc)
- clk_set_rate(scale3d.clk_3d_emc,
- clk_round_rate(scale3d.clk_3d_emc, UINT_MAX));
+ if (is_tegra_camera_on())
+ clk_set_rate(scale3d.clk_3d, CAMERA_3D_CLK);
+ else
+ clk_set_rate(scale3d.clk_3d, scale3d.max_rate_3d);
+ if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) {
+ if (is_tegra_camera_on())
+ clk_set_rate(scale3d.clk_3d2, CAMERA_3D_CLK);
+ else
+ clk_set_rate(scale3d.clk_3d2,
+ scale3d.max_rate_3d);
+ }
+ if (scale3d.p_scale_emc) {
+ if (is_tegra_camera_on())
+ clk_set_rate(scale3d.clk_3d_emc,
+ CAMERA_3D_EMC_CLK);
+ else
+ clk_set_rate(scale3d.clk_3d_emc,
+ clk_round_rate(scale3d.clk_3d_emc,
+ UINT_MAX));
+ }
}
}
@@ -207,15 +273,6 @@ static void scale3d_enable(int enable)
reset_3d_clocks();
}
-static void reset_scaling_counters(ktime_t time)
-{
- scale3d.idle_total = 0;
- scale3d.idle_short_term_total = 0;
- scale3d.last_idle = time;
- scale3d.last_short_term_idle = time;
- scale3d.idle_frame = time;
-}
-
/* scaling_adjust - use scale up / scale down hint counts to adjust scaling
* parameters.
*
@@ -228,8 +285,6 @@ static void reset_scaling_counters(ktime_t time)
*
* the parameters adjusted are
*
- * * fast_response time
- * * period - time for scaling down estimate
* * idle_min percentage
* * idle_max percentage
*/
@@ -242,13 +297,11 @@ static void reset_scaling_counters(ktime_t time)
static void scaling_adjust(ktime_t time)
{
long hint_ratio;
- long fast_response_adjustment;
- long period_adjustment;
int idle_min_adjustment;
int idle_max_adjustment;
unsigned long dt;
- dt = (unsigned long) ktime_us_delta(time, scale3d.last_tweak);
+ dt = (unsigned long) ktime_us_delta(time, scale3d.last_adjust);
if (dt < SCALING_ADJUST_PERIOD)
return;
@@ -256,13 +309,9 @@ static void scaling_adjust(ktime_t time)
(scale3d.slow_down_count + 1);
if (hint_ratio > HINT_RATIO_MAX) {
- fast_response_adjustment = -((int) scale3d.p_fast_response) / 4;
- period_adjustment = scale3d.p_period / 2;
idle_min_adjustment = scale3d.p_idle_min;
idle_max_adjustment = scale3d.p_idle_max;
} else if (hint_ratio < HINT_RATIO_MIN) {
- fast_response_adjustment = scale3d.p_fast_response / 2;
- period_adjustment = -((int) scale3d.p_period) / 4;
idle_min_adjustment = -((int) scale3d.p_idle_min) / 2;
idle_max_adjustment = -((int) scale3d.p_idle_max) / 2;
} else {
@@ -277,33 +326,23 @@ static void scaling_adjust(ktime_t time)
diff *= 2;
}
- fast_response_adjustment = diff *
- (scale3d.p_fast_response / (HINT_RATIO_DIFF * 2));
- period_adjustment =
- diff * (scale3d.p_period / HINT_RATIO_DIFF);
idle_min_adjustment =
(factor * (int) scale3d.p_idle_min) / HINT_RATIO_DIFF;
idle_max_adjustment =
(factor * (int) scale3d.p_idle_max) / HINT_RATIO_DIFF;
}
- scale3d.fast_response =
- scale3d.p_fast_response + fast_response_adjustment;
- scale3d.period = scale3d.p_period + period_adjustment;
- scale3d.idle_min = scale3d.p_idle_min + idle_min_adjustment;
+ scale3d.idle_min = scale3d.p_idle_min + idle_min_adjustment;
scale3d.idle_max = scale3d.p_idle_max + idle_max_adjustment;
- if (scale3d.p_verbosity >= 10)
- pr_info("scale3d stats: + %d - %d (/ %d) f %u p %u min %u max %u\n",
+ if (scale3d.p_verbosity & GR3D_PRINT_STATS)
+ pr_info("scale3d stats: + %d - %d min %u max %u\n",
scale3d.fast_up_count, scale3d.slow_down_count,
- scale3d.fast_responses, scale3d.fast_response,
- scale3d.period, scale3d.idle_min, scale3d.idle_max);
+ scale3d.idle_min, scale3d.idle_max);
scale3d.fast_up_count = 0;
scale3d.slow_down_count = 0;
- scale3d.fast_responses = 0;
- scale3d.last_down = time;
- scale3d.last_tweak = time;
+ scale3d.last_adjust = time;
}
#undef SCALING_ADJUST_PERIOD
@@ -316,61 +355,101 @@ static void scaling_state_check(ktime_t time)
{
unsigned long dt;
- /* adjustment: set scale parameters (fast_response, period) +/- 25%
+ /* adjustment: set scale parameters (idle_min, idle_max) +/- 25%
* based on ratio of scale up to scale down hints
*/
if (scale3d.p_adjust)
scaling_adjust(time);
else {
- scale3d.fast_response = scale3d.p_fast_response;
- scale3d.period = scale3d.p_period;
scale3d.idle_min = scale3d.p_idle_min;
scale3d.idle_max = scale3d.p_idle_max;
}
- /* check for load peaks */
- dt = (unsigned long) ktime_us_delta(time, scale3d.fast_frame);
- if (dt > scale3d.fast_response) {
- unsigned long idleness =
- (scale3d.idle_short_term_total * 100) / dt;
- scale3d.fast_responses++;
- scale3d.fast_frame = time;
- /* if too busy, scale up */
- if (idleness < scale3d.idle_min) {
- scale3d.is_scaled = 0;
- scale3d.fast_up_count++;
- if (scale3d.p_verbosity >= 5)
- pr_info("scale3d: %ld%% busy\n",
- 100 - idleness);
-
- reset_3d_clocks();
- reset_scaling_counters(time);
- return;
- }
- scale3d.idle_short_term_total = 0;
- scale3d.last_short_term_idle = time;
+ dt = (unsigned long) ktime_us_delta(time, scale3d.last_scale);
+ if (dt < scale3d.p_estimation_window)
+ return;
+
+ scale3d.last_scale = time;
+
+ /* if too busy, scale up */
+ if (scale3d.idle_estimate < scale3d.idle_min) {
+ scale3d.is_scaled = 0;
+ scale3d.fast_up_count++;
+ if (scale3d.p_verbosity & GR3D_PRINT_BUSY)
+ pr_info("scale3d: %ld/1000 busy\n",
+ 1000 - scale3d.idle_estimate);
+
+ reset_3d_clocks();
+ return;
}
- dt = (unsigned long) ktime_us_delta(time, scale3d.idle_frame);
- if (dt > scale3d.period) {
- unsigned long idleness = (scale3d.idle_total * 100) / dt;
+ if (scale3d.p_verbosity & GR3D_PRINT_IDLE)
+ pr_info("scale3d: idle %lu/1000\n",
+ scale3d.idle_estimate);
- if (scale3d.p_verbosity >= 5)
- pr_info("scale3d: idle %lu, ~%lu%%\n",
- scale3d.idle_total, idleness);
+ if (scale3d.idle_estimate > scale3d.idle_max) {
+ if (!scale3d.is_scaled)
+ scale3d.is_scaled = 1;
- if (idleness > scale3d.idle_max) {
- if (!scale3d.is_scaled) {
- scale3d.is_scaled = 1;
- scale3d.last_down = time;
- }
- scale3d.slow_down_count++;
- /* if idle time is high, clock down */
- scale3d.scale = 100 - (idleness - scale3d.idle_min);
- schedule_work(&scale3d.work);
- }
+ scale3d.slow_down_count++;
+ /* if idle time is high, clock down */
+ scale3d.scale =
+ 100 - (scale3d.idle_estimate - scale3d.idle_min) / 10;
+ schedule_work(&scale3d.work);
+ }
+}
+
+/* the idle estimate is done by keeping 2 time stamps, initially set to the
+ * same time. Once the estimation_window time has been exceeded, one time
+ * stamp is moved up to the current time. The idle estimate is calculated
+ * based on the idle time percentage from the earlier estimate. The next time
+ * an estimation_window time is exceeded, the previous idle time and estimates
+ * are moved up - this is intended to prevent abrupt changes to the idle
+ * estimate.
+ */
+static void update_load_estimate(int idle)
+{
+ unsigned long window;
+ unsigned long t;
+
+ ktime_t now = ktime_get();
+ t = ktime_us_delta(now, scale3d.last_notification);
- reset_scaling_counters(time);
+ /* if the last event was over GR3D_TIMEFRAME usec ago (1 sec), the
+ * current load tracking data is probably stale
+ */
+ if (t > GR3D_TIMEFRAME) {
+ scale3d.is_idle = idle;
+ scale3d.last_notification = now;
+ scale3d.estimation_window = now;
+ scale3d.last_estimation_window = now;
+ scale3d.total_idle = 0;
+ scale3d.last_total_idle = 0;
+ scale3d.idle_estimate = idle ? 1000 : 0;
+ return;
+ }
+
+ if (scale3d.is_idle) {
+ scale3d.total_idle += t;
+ scale3d.last_total_idle += t;
+ }
+
+ scale3d.is_idle = idle;
+ scale3d.last_notification = now;
+
+ window = ktime_us_delta(now, scale3d.last_estimation_window);
+ /* prevent division by 0 if events come in less than 1 usec apart */
+ if (window > 0)
+ scale3d.idle_estimate =
+ (1000 * scale3d.last_total_idle) / window;
+
+ /* move up to the last estimation window */
+ if (ktime_us_delta(now, scale3d.estimation_window) >
+ scale3d.p_estimation_window) {
+ scale3d.last_estimation_window = scale3d.estimation_window;
+ scale3d.last_total_idle = scale3d.total_idle;
+ scale3d.total_idle = 0;
+ scale3d.estimation_window = now;
}
}
@@ -378,65 +457,226 @@ void nvhost_scale3d_notify_idle(struct nvhost_device *dev)
{
ktime_t t;
unsigned long dt;
+ int delay;
if (!scale3d.enable)
return;
- mutex_lock(&scale3d.lock);
+ update_load_estimate(1);
t = ktime_get();
- if (scale3d.is_idle) {
- dt = ktime_us_delta(t, scale3d.last_idle);
- scale3d.idle_total += dt;
- dt = ktime_us_delta(t, scale3d.last_short_term_idle);
- scale3d.idle_short_term_total += dt;
- } else
- scale3d.is_idle = 1;
+ /* if throughput hint enabled, and last hint is recent enough, return */
+ if (scale3d.p_use_throughput_hint) {
+ dt = ktime_us_delta(t, scale3d.last_throughput_hint);
+ if (dt < GR3D_TIMEFRAME)
+ return;
+ }
- scale3d.last_idle = t;
- scale3d.last_short_term_idle = t;
+ mutex_lock(&scale3d.lock);
- scaling_state_check(scale3d.last_idle);
+ scaling_state_check(t);
- /* delay idle_max % of 2 * fast_response time (given in microseconds) */
- schedule_delayed_work(&scale3d.idle_timer,
- msecs_to_jiffies((scale3d.idle_max * scale3d.fast_response)
- / 50000));
+ /* delay idle_max % of 2 * estimation_window (given in microseconds) */
+ delay = (scale3d.idle_max * scale3d.p_estimation_window) / 500000;
+ schedule_delayed_work(&scale3d.idle_timer, msecs_to_jiffies(delay));
mutex_unlock(&scale3d.lock);
}
void nvhost_scale3d_notify_busy(struct nvhost_device *dev)
{
- unsigned long idle;
- unsigned long short_term_idle;
ktime_t t;
if (!scale3d.enable)
return;
- mutex_lock(&scale3d.lock);
-
- cancel_delayed_work(&scale3d.idle_timer);
+ update_load_estimate(0);
t = ktime_get();
- if (scale3d.is_idle) {
- idle = (unsigned long)
- ktime_us_delta(t, scale3d.last_idle);
- scale3d.idle_total += idle;
- short_term_idle =
- ktime_us_delta(t, scale3d.last_short_term_idle);
- scale3d.idle_short_term_total += short_term_idle;
- scale3d.is_idle = 0;
+ /* if throughput hint enabled, and last hint is recent enough, return */
+ if (scale3d.p_use_throughput_hint) {
+ unsigned long dt;
+ dt = ktime_us_delta(t, scale3d.last_throughput_hint);
+ if (dt < GR3D_TIMEFRAME)
+ return;
}
+ mutex_lock(&scale3d.lock);
+
+ cancel_delayed_work(&scale3d.idle_timer);
scaling_state_check(t);
mutex_unlock(&scale3d.lock);
}
+struct score {
+ int size; /* number of elements */
+ int pos; /* position in ring buffer */
+ int count; /* actual item count */
+ unsigned int sum; /* running sum */
+ unsigned int prev; /* previous score after 'reset' operation */
+ unsigned int list[]; /* ring buffer */
+};
+
+static struct score *score_init(int capacity)
+{
+ struct score *s;
+
+ s = kzalloc(sizeof(struct score) + capacity * sizeof(int), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->size = capacity;
+
+ return s;
+}
+
+static void score_delete(struct score *s)
+{
+ kfree(s);
+}
+
+#define score_get_average(s) ((s)->count ? (s)->sum / (s)->count : 0)
+
+static void score_add(struct score *s, unsigned int reading)
+{
+ if (s->count < s->size) {
+ s->sum += reading;
+ s->count++;
+ } else
+ s->sum = s->sum - s->list[s->pos] + reading;
+
+ s->list[s->pos] = reading;
+ s->pos = (s->pos + 1) % s->size;
+}
+
+
+static unsigned int score_reset(struct score *s)
+{
+ s->prev = s->sum;
+
+ s->count = 0;
+ s->pos = 0;
+ s->sum = 0;
+
+ return s->prev;
+}
+
+int freqlist_up(long target, int steps)
+{
+ int i, pos;
+
+ for (i = 0; i < scale3d.freq_count; i++)
+ if (scale3d.freqlist[i] >= target)
+ break;
+
+ pos = min(scale3d.freq_count - 1, i + steps);
+ return scale3d.freqlist[pos];
+}
+
+int freqlist_down(long target, int steps)
+{
+ int i, pos;
+
+ for (i = scale3d.freq_count - 1; i >= 0; i--)
+ if (scale3d.freqlist[i] <= target)
+ break;
+
+ pos = max(0, i - steps);
+ return scale3d.freqlist[pos];
+}
+
+static struct score *busy_history;
+static struct score *hint_history;
+
+/* When a throughput hint is given, perform scaling based on the hint and on
+ * the current idle estimation. This is done as follows:
+ *
+ * 1. On moderate loads force min frequency if the throughput hint is not too
+ * low.
+ * 2. Otherwise, calculate target-rate = max-rate * load-percentage
+ * 3. Unless the current or average throughput hint is below the minimum
+ * limit, in which case, choose a higher rate
+ * 4. Or the average throughput hint is above the maximum limit, in which case,
+ * choose a lower rate.
+ */
+void nvhost_scale3d_set_throughput_hint(int hint)
+{
+ ktime_t now;
+ long busy;
+ long curr;
+ long target;
+ long dt;
+ int avg_busy, avg_hint;
+
+ if (!scale3d.enable)
+ return;
+
+ if (!scale3d.p_use_throughput_hint)
+ return;
+
+ if (scale3d.p_verbosity & GR3D_PRINT_HINT)
+ pr_info("3fds: idle %ld, hint %d\n",
+ scale3d.idle_estimate, hint);
+
+ now = ktime_get();
+ dt = ktime_us_delta(now, scale3d.last_throughput_hint);
+ if (dt > GR3D_TIMEFRAME) {
+ score_reset(busy_history);
+ score_reset(hint_history);
+ }
+
+ scale3d.last_throughput_hint = now;
+
+ busy = 1000 - scale3d.idle_estimate;
+ curr = clk_get_rate(scale3d.clk_3d);
+ target = scale3d.min_rate_3d;
+
+ score_add(busy_history, busy);
+ score_add(hint_history, hint);
+
+ avg_busy = score_get_average(busy_history);
+ avg_hint = score_get_average(hint_history);
+
+ if (busy > 0)
+ target = (curr / 1000) * busy;
+
+ /* In practice, running the gpu at min frequency is typically
+ * sufficient to keep up performance at loads up to 70% on cases,
+ * but the average hint value is tested to keep performance up if
+ * needed.
+ */
+ if (avg_busy <= scale3d.p_busy_cutoff &&
+ avg_hint >= scale3d.p_throughput_lower_limit)
+ target = scale3d.min_rate_3d;
+ else {
+ target = (scale3d.max_rate_3d / 1000) * avg_busy;
+
+ /* Scale up if either the current hint or the running average
+ * are below the target to prevent performance drop.
+ */
+ if (hint <= scale3d.p_throughput_lo_limit ||
+ avg_hint <= scale3d.p_throughput_lo_limit) {
+ if (target < curr)
+ target = curr;
+ target = freqlist_up(target, scale3d.p_scale_step);
+ } else if (avg_hint >= scale3d.p_throughput_hi_limit) {
+ if (target > curr)
+ target = curr;
+ target = freqlist_down(target, scale3d.p_scale_step);
+ }
+ }
+
+ scale_to_freq(target);
+
+ if (scale3d.p_verbosity & GR3D_PRINT_TARGET)
+ pr_info("3dfs: busy %ld <%d>, curr %ld, t %ld, hint %d <%d>\n",
+ busy, avg_busy, curr / 1000000, target, hint, avg_hint);
+}
+EXPORT_SYMBOL(nvhost_scale3d_set_throughput_hint);
+
static void scale3d_idle_handler(struct work_struct *work)
{
int notify_idle = 0;
@@ -458,19 +698,6 @@ static void scale3d_idle_handler(struct work_struct *work)
nvhost_scale3d_notify_idle(NULL);
}
-void nvhost_scale3d_reset()
-{
- ktime_t t;
-
- if (!scale3d.enable)
- return;
-
- t = ktime_get();
- mutex_lock(&scale3d.lock);
- reset_scaling_counters(t);
- mutex_unlock(&scale3d.lock);
-}
-
/*
* debugfs parameters to control 3d clock scaling
*/
@@ -495,13 +722,17 @@ void nvhost_scale3d_debug_init(struct dentry *de)
} \
} while (0)
- CREATE_SCALE3D_FILE(fast_response);
+ CREATE_SCALE3D_FILE(estimation_window);
CREATE_SCALE3D_FILE(idle_min);
CREATE_SCALE3D_FILE(idle_max);
- CREATE_SCALE3D_FILE(period);
CREATE_SCALE3D_FILE(adjust);
CREATE_SCALE3D_FILE(scale_emc);
CREATE_SCALE3D_FILE(emc_dip);
+ CREATE_SCALE3D_FILE(use_throughput_hint);
+ CREATE_SCALE3D_FILE(throughput_hi_limit);
+ CREATE_SCALE3D_FILE(throughput_lo_limit);
+ CREATE_SCALE3D_FILE(throughput_lower_limit);
+ CREATE_SCALE3D_FILE(scale_step);
CREATE_SCALE3D_FILE(verbosity);
#undef CREATE_SCALE3D_FILE
}
@@ -532,12 +763,17 @@ static ssize_t enable_3d_scaling_store(struct device *dev,
static DEVICE_ATTR(enable_3d_scaling, S_IRUGO | S_IWUSR,
enable_3d_scaling_show, enable_3d_scaling_store);
+#define MAX_FREQ_COUNT 0x40 /* 64 frequencies should be enough for anyone */
+
void nvhost_scale3d_init(struct nvhost_device *d)
{
if (!scale3d.init) {
int error;
unsigned long max_emc, min_emc;
long correction;
+ long rate;
+ int freqs[MAX_FREQ_COUNT];
+
mutex_init(&scale3d.lock);
INIT_WORK(&scale3d.work, scale3d_clocks_handler);
@@ -632,30 +868,74 @@ void nvhost_scale3d_init(struct nvhost_device *d)
POW2(scale3d.max_rate_3d - scale3d.emc_xmid);
scale3d.emc_dip_offset -= correction;
+ scale3d.is_idle = 1;
+
/* set scaling parameter defaults */
scale3d.enable = 1;
- scale3d.period = scale3d.p_period = 100000;
- scale3d.idle_min = scale3d.p_idle_min = 10;
- scale3d.idle_max = scale3d.p_idle_max = 15;
- scale3d.fast_response = scale3d.p_fast_response = 7000;
+ scale3d.idle_min = scale3d.p_idle_min = 100;
+ scale3d.idle_max = scale3d.p_idle_max = 150;
scale3d.p_scale_emc = 1;
scale3d.p_emc_dip = 1;
scale3d.p_verbosity = 0;
scale3d.p_adjust = 1;
+ scale3d.p_use_throughput_hint = 1;
+ scale3d.p_throughput_lower_limit = 940;
+ scale3d.p_throughput_lo_limit = 990;
+ scale3d.p_throughput_hi_limit = 1010;
+ scale3d.p_scale_step = 1;
+ scale3d.p_estimation_window = 8000;
+ scale3d.p_busy_cutoff = 750;
error = device_create_file(&d->dev,
&dev_attr_enable_3d_scaling);
if (error)
dev_err(&d->dev, "failed to create sysfs attributes");
+ rate = 0;
+ scale3d.freq_count = 0;
+ while (rate <= scale3d.max_rate_3d) {
+ long rounded_rate;
+ if (unlikely(scale3d.freq_count == MAX_FREQ_COUNT)) {
+ pr_err("%s: too many frequencies\n", __func__);
+ break;
+ }
+ rounded_rate =
+ clk_round_rate(scale3d.clk_3d, rate);
+ freqs[scale3d.freq_count++] = rounded_rate;
+ rate = rounded_rate + 2000;
+ }
+ scale3d.freqlist =
+ kmalloc(scale3d.freq_count * sizeof(int), GFP_KERNEL);
+ if (scale3d.freqlist == NULL)
+ pr_err("%s: can\'t allocate freq table\n", __func__);
+
+ memcpy(scale3d.freqlist, freqs,
+ scale3d.freq_count * sizeof(int));
+
+ busy_history = score_init(GR3D_FRAME_SPAN);
+ if (busy_history == NULL)
+ pr_err("%s: can\'t init load tracking array\n",
+ __func__);
+
+ hint_history = score_init(GR3D_FRAME_SPAN);
+ if (hint_history == NULL)
+ pr_err("%s: can\'t init throughput tracking array\n",
+ __func__);
+
scale3d.init = 1;
}
-
- nvhost_scale3d_reset();
}
void nvhost_scale3d_deinit(struct nvhost_device *dev)
{
device_remove_file(&dev->dev, &dev_attr_enable_3d_scaling);
scale3d.init = 0;
+ if (scale3d.freqlist != NULL) {
+ kfree(scale3d.freqlist);
+ scale3d.freq_count = 0;
+ scale3d.freqlist = NULL;
+ }
+
+ score_delete(busy_history);
+ score_delete(hint_history);
}
diff --git a/drivers/video/tegra/host/host1x/host1x.c b/drivers/video/tegra/host/host1x/host1x.c
index 33ebc1ff5d22..31899c78065b 100644
--- a/drivers/video/tegra/host/host1x/host1x.c
+++ b/drivers/video/tegra/host/host1x/host1x.c
@@ -308,6 +308,19 @@ static int power_off_host(struct nvhost_device *dev)
return 0;
}
+static void clock_on_host(struct nvhost_device *dev)
+{
+ struct nvhost_master *host = nvhost_get_drvdata(dev);
+ nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
+}
+
+static int clock_off_host(struct nvhost_device *dev)
+{
+ struct nvhost_master *host = nvhost_get_drvdata(dev);
+ nvhost_intr_stop(&host->intr);
+ return 0;
+}
+
static int __devinit nvhost_user_init(struct nvhost_master *host)
{
int err, devno;
@@ -516,6 +529,8 @@ static struct nvhost_driver nvhost_driver = {
},
.finalize_poweron = power_on_host,
.prepare_poweroff = power_off_host,
+ .finalize_clockon = clock_on_host,
+ .prepare_clockoff = clock_off_host,
};
static int __init nvhost_mod_init(void)
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c
index 2e7ff5783a37..5a29ff652efe 100644
--- a/drivers/video/tegra/host/host1x/host1x_cdma.c
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.c
@@ -233,12 +233,15 @@ static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
/* after CPU incr, ensure shadow is up to date */
nvhost_syncpt_update_min(&dev->syncpt, cdma->timeout.syncpt_id);
- /* update WAITBASE_3D by same number of incrs */
- if (waitbases) {
+ /* Synchronize wait bases. 2D wait bases are synchronized with
+ * syncpoint 19. Hence wait bases are not updated when syncptid=18. */
+
+ if (cdma->timeout.syncpt_id != NVSYNCPT_2D_0 && waitbases) {
void __iomem *p;
p = dev->sync_aperture + host1x_sync_syncpt_base_0_r() +
- (ffs(waitbases) * sizeof(u32));
+ (__ffs(waitbases) * sizeof(u32));
writel(syncval, p);
+ dev->syncpt.base_val[__ffs(waitbases)] = syncval;
}
/* NOP all the PB slots */
@@ -486,7 +489,7 @@ static void cdma_timeout_handler(struct work_struct *work)
/* stop HW, resetting channel/module */
cdma_op().timeout_teardown_begin(cdma);
- nvhost_cdma_update_sync_queue(cdma, sp, dev->dev);
+ nvhost_cdma_update_sync_queue(cdma, sp, ch->dev);
mutex_unlock(&cdma->lock);
}
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c
index 9e9fc25dc966..0274413ff698 100644
--- a/drivers/video/tegra/host/host1x/host1x_channel.c
+++ b/drivers/video/tegra/host/host1x/host1x_channel.c
@@ -365,7 +365,7 @@ static int host1x_channel_read_3d_reg(
if (hwctx_to_save) {
syncpt_incrs += hwctx_to_save->save_incrs;
hwctx_to_save->hwctx.valid = true;
- channel->ctxhandler->get(&hwctx_to_save->hwctx);
+ nvhost_job_get_hwctx(job, &hwctx_to_save->hwctx);
}
channel->cur_ctx = hwctx;
if (channel->cur_ctx && channel->cur_ctx->valid) {
@@ -470,7 +470,8 @@ static int host1x_channel_read_3d_reg(
wait_event(wq,
nvhost_syncpt_is_expired(&nvhost_get_host(channel->dev)->syncpt,
p->syncpt, syncval - 2));
- nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, ref);
+ nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, p->syncpt,
+ ref);
/* Read the register value from FIFO */
err = host1x_drain_read_fifo(channel, value, 1, &pending);
@@ -580,7 +581,6 @@ static int host1x_save_context(struct nvhost_channel *ch)
}
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;
@@ -623,7 +623,7 @@ static int host1x_save_context(struct nvhost_channel *ch)
nvhost_syncpt_is_expired(&nvhost_get_host(ch->dev)->syncpt,
syncpt_id, syncpt_val));
- nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, ref);
+ nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, syncpt_id, ref);
nvhost_cdma_update(&ch->cdma);
diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c
index 62fd07cbb9ba..facb818a0c24 100644
--- a/drivers/video/tegra/host/host1x/host1x_intr.c
+++ b/drivers/video/tegra/host/host1x/host1x_intr.c
@@ -131,6 +131,16 @@ static void t20_intr_enable_syncpt_intr(struct nvhost_intr *intr, u32 id)
BIT_WORD(id) * REGISTER_STRIDE);
}
+static void t20_intr_disable_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_MASK(id), sync_regs +
+ host1x_sync_syncpt_thresh_int_disable_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);
@@ -140,7 +150,7 @@ static void t20_intr_disable_all_syncpt_intrs(struct nvhost_intr *intr)
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 +
+ writel(0xffffffffu, sync_regs +
host1x_sync_syncpt_thresh_int_disable_r() +
reg);
@@ -276,6 +286,7 @@ static const struct nvhost_intr_ops host1x_intr_ops = {
.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_syncpt_intr = t20_intr_disable_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,
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
index c738700469c6..d76ee0108eef 100644
--- a/drivers/video/tegra/host/mpe/mpe.c
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -212,7 +212,7 @@ struct save_info {
unsigned int restore_count;
};
-static void __init save_begin(struct host1x_hwctx_handler *h, u32 *ptr)
+static void 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);
@@ -229,7 +229,7 @@ static void __init save_begin(struct host1x_hwctx_handler *h, u32 *ptr)
}
#define SAVE_BEGIN_SIZE 5
-static void __init save_direct(u32 *ptr, u32 start_reg, u32 count)
+static void save_direct(u32 *ptr, u32 start_reg, u32 count)
{
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
host1x_uclass_indoff_r(), 1);
@@ -239,7 +239,7 @@ static void __init save_direct(u32 *ptr, u32 start_reg, u32 count)
}
#define SAVE_DIRECT_SIZE 3
-static void __init save_set_ram_cmd(u32 *ptr, u32 cmd_reg, u32 count)
+static void save_set_ram_cmd(u32 *ptr, u32 cmd_reg, u32 count)
{
ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID,
cmd_reg, 1);
@@ -247,7 +247,7 @@ static void __init save_set_ram_cmd(u32 *ptr, u32 cmd_reg, u32 count)
}
#define SAVE_SET_RAM_CMD_SIZE 2
-static void __init save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
+static void save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
{
ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
host1x_uclass_indoff_r(), 1);
@@ -261,7 +261,7 @@ static void __init save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
}
#define SAVE_READ_RAM_DATA_NASTY_SIZE 5
-static void __init save_end(struct host1x_hwctx_handler *h, u32 *ptr)
+static void 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,
@@ -275,7 +275,7 @@ static void __init save_end(struct host1x_hwctx_handler *h, u32 *ptr)
}
#define SAVE_END_SIZE 5
-static void __init setup_save_regs(struct save_info *info,
+static void setup_save_regs(struct save_info *info,
const struct hwctx_reginfo *regs,
unsigned int nr_regs)
{
@@ -304,7 +304,7 @@ static void __init setup_save_regs(struct save_info *info,
info->restore_count = restore_count;
}
-static void __init setup_save_ram_nasty(struct save_info *info, unsigned words,
+static void setup_save_ram_nasty(struct save_info *info, unsigned words,
unsigned cmd_reg, unsigned data_reg)
{
u32 *ptr = info->ptr;
@@ -330,7 +330,7 @@ static void __init setup_save_ram_nasty(struct save_info *info, unsigned words,
info->restore_count = restore_count;
}
-static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
+static void setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
{
struct save_info info = {
ptr,
@@ -553,7 +553,7 @@ struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(u32 syncpt,
p->save_buf = mem_op().alloc(memmgr, p->save_size * 4, 32,
mem_mgr_flag_write_combine);
- if (IS_ERR(p->save_buf)) {
+ if (IS_ERR_OR_NULL(p->save_buf)) {
p->save_buf = NULL;
return NULL;
}
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 06005c423a21..5bde55ad2ff5 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -101,8 +101,17 @@ void nvhost_module_reset(struct nvhost_device *dev)
static void to_state_clockgated_locked(struct nvhost_device *dev)
{
+ struct nvhost_driver *drv = to_nvhost_driver(dev->dev.driver);
+
if (dev->powerstate == NVHOST_POWER_STATE_RUNNING) {
- int i;
+ int i, err;
+ if (drv->prepare_clockoff) {
+ err = drv->prepare_clockoff(dev);
+ if (err) {
+ dev_err(&dev->dev, "error clock gating");
+ return;
+ }
+ }
for (i = 0; i < dev->num_clks; i++)
clk_disable(dev->clk[i]);
if (dev->dev.parent)
@@ -141,6 +150,14 @@ static void to_state_running_locked(struct nvhost_device *dev)
}
}
+ /* Invoke callback after enabling clock. This is used for
+ * re-enabling host1x interrupts. */
+ if (prev_state == NVHOST_POWER_STATE_CLOCKGATED
+ && drv->finalize_clockon)
+ drv->finalize_clockon(dev);
+
+ /* Invoke callback after power un-gating. This is used for
+ * restoring context. */
if (prev_state == NVHOST_POWER_STATE_POWERGATED
&& drv->finalize_poweron)
drv->finalize_poweron(dev);
@@ -343,15 +360,17 @@ void nvhost_module_remove_client(struct nvhost_device *dev, void *priv)
{
int i;
struct nvhost_module_client *m;
+ int found = 0;
mutex_lock(&client_list_lock);
list_for_each_entry(m, &dev->client_list, node) {
if (priv == m->priv) {
list_del(&m->node);
+ found = 1;
break;
}
}
- if (m) {
+ if (found) {
kfree(m);
for (i = 0; i < dev->num_clks; i++)
nvhost_module_update_rate(dev, i);
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
index 38a04f151e87..9788d32bd4a9 100644
--- a/drivers/video/tegra/host/nvhost_intr.c
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -210,7 +210,9 @@ static int process_wait_list(struct nvhost_intr *intr,
remove_completed_waiters(&syncpt->wait_head, threshold, completed);
empty = list_empty(&syncpt->wait_head);
- if (!empty)
+ if (empty)
+ intr_op().disable_syncpt_intr(intr, syncpt->id);
+ else
reset_threshold_interrupt(intr, &syncpt->wait_head,
syncpt->id);
@@ -327,14 +329,20 @@ void *nvhost_intr_alloc_waiter()
GFP_KERNEL|__GFP_REPEAT);
}
-void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref)
+void nvhost_intr_put_ref(struct nvhost_intr *intr, u32 id, void *ref)
{
struct nvhost_waitlist *waiter = ref;
+ struct nvhost_intr_syncpt *syncpt;
+ struct nvhost_master *host = intr_to_dev(intr);
while (atomic_cmpxchg(&waiter->state,
WLS_PENDING, WLS_CANCELLED) == WLS_REMOVED)
schedule();
+ syncpt = intr->syncpt + id;
+ (void)process_wait_list(intr, syncpt,
+ nvhost_syncpt_update_min(&host->syncpt, id));
+
kref_put(&waiter->refcount, waiter_release);
}
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
index cf0b6b9e8934..d4a6157eced1 100644
--- a/drivers/video/tegra/host/nvhost_intr.h
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -104,7 +104,7 @@ void *nvhost_intr_alloc_waiter(void);
* You must call this if you passed non-NULL as ref.
* @ref the ref returned from nvhost_intr_add_action()
*/
-void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref);
+void nvhost_intr_put_ref(struct nvhost_intr *intr, u32 id, void *ref);
int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync);
void nvhost_intr_deinit(struct nvhost_intr *intr);
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
index f93d7df1a552..f0f7e64d4504 100644
--- a/drivers/video/tegra/host/nvhost_job.c
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -34,19 +34,27 @@
/* Magic to use to fill freed handle slots */
#define BAD_MAGIC 0xdeadbeef
-static int job_size(struct nvhost_submit_hdr_ext *hdr)
+static size_t job_size(struct nvhost_submit_hdr_ext *hdr)
{
- 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;
+ s64 num_relocs = hdr ? (int)hdr->num_relocs : 0;
+ s64 num_waitchks = hdr ? (int)hdr->num_waitchks : 0;
+ s64 num_cmdbufs = hdr ? (int)hdr->num_cmdbufs : 0;
+ s64 num_unpins = num_cmdbufs + num_relocs;
+ s64 total;
- return sizeof(struct nvhost_job)
+ if(num_relocs < 0 || num_waitchks < 0 || num_cmdbufs < 0)
+ return 0;
+
+ total = sizeof(struct nvhost_job)
+ 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);
+
+ if(total > ULONG_MAX)
+ return 0;
+ return (size_t)total;
}
static void init_fields(struct nvhost_job *job,
@@ -63,7 +71,11 @@ static void init_fields(struct nvhost_job *job,
job->priority = priority;
job->clientid = clientid;
- /* Redistribute memory to the structs */
+ /*
+ * Redistribute memory to the structs.
+ * Overflows and negative conditions have
+ * already been checked in job_alloc().
+ */
mem += sizeof(struct nvhost_job);
job->relocarray = num_relocs ? mem : NULL;
mem += num_relocs * sizeof(struct nvhost_reloc);
@@ -91,8 +103,11 @@ struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
int clientid)
{
struct nvhost_job *job = NULL;
+ size_t size = job_size(hdr);
- job = vzalloc(job_size(hdr));
+ if(!size)
+ goto error;
+ job = vzalloc(size);
if (!job)
goto error;
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
index 9fa7d0652c1f..38c28ca116e7 100644
--- a/drivers/video/tegra/host/nvhost_syncpt.c
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -235,7 +235,7 @@ int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
check_count++;
}
}
- nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), ref);
+ nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), id, ref);
done:
nvhost_module_idle(syncpt_to_dev(sp)->dev);
@@ -344,7 +344,7 @@ static ssize_t syncpt_min_show(struct kobject *kobj,
struct nvhost_syncpt_attr *syncpt_attr =
container_of(attr, struct nvhost_syncpt_attr, attr);
- return snprintf(buf, PAGE_SIZE, "%d",
+ return snprintf(buf, PAGE_SIZE, "%u",
nvhost_syncpt_read(&syncpt_attr->host->syncpt,
syncpt_attr->id));
}
@@ -355,7 +355,7 @@ static ssize_t syncpt_max_show(struct kobject *kobj,
struct nvhost_syncpt_attr *syncpt_attr =
container_of(attr, struct nvhost_syncpt_attr, attr);
- return snprintf(buf, PAGE_SIZE, "%d",
+ return snprintf(buf, PAGE_SIZE, "%u",
nvhost_syncpt_read_max(&syncpt_attr->host->syncpt,
syncpt_attr->id));
}
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
index 0c8d626a4d67..334d598d5c0b 100644
--- a/drivers/video/tegra/host/t30/t30.c
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -142,7 +142,7 @@ static struct nvhost_device tegra_gr2d02_device = {
.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", 0},
{"epp", 0},
{"emc", 300000000} },
NVHOST_MODULE_NO_POWERGATE_IDS,
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
index b7fd695d04ee..a0dcf26337f8 100644
--- a/drivers/video/tegra/nvmap/nvmap.c
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -3,7 +3,7 @@
*
* Memory manager for Tegra GPU
*
- * 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
@@ -271,7 +271,7 @@ int nvmap_pin_ids(struct nvmap_client *client,
* if the caller crashes after pinning a global handle, the handle
* will be permanently leaked. */
nvmap_ref_lock(client);
- for (i = 0; i < nr && !ret; i++) {
+ for (i = 0; i < nr; i++) {
ref = _nvmap_validate_id_locked(client, ids[i]);
if (ref) {
atomic_inc(&ref->pin);
@@ -280,19 +280,19 @@ int nvmap_pin_ids(struct nvmap_client *client,
struct nvmap_handle *verify;
nvmap_ref_unlock(client);
verify = nvmap_validate_get(client, ids[i]);
- if (verify)
+ if (verify) {
nvmap_warn(client, "%s pinning unreferenced "
"handle %p\n",
current->group_leader->comm, h[i]);
- else
+ } else {
+ h[i] = NULL;
ret = -EPERM;
+ }
nvmap_ref_lock(client);
}
}
nvmap_ref_unlock(client);
- nr = i;
-
if (ret)
goto out;
@@ -317,6 +317,9 @@ out:
if (ret) {
nvmap_ref_lock(client);
for (i = 0; i < nr; i++) {
+ if(!ids[i])
+ continue;
+
ref = _nvmap_validate_id_locked(client, ids[i]);
if (!ref) {
nvmap_warn(client, "%s freed handle %p "
@@ -330,7 +333,8 @@ out:
nvmap_ref_unlock(client);
for (i = 0; i < nr; i++)
- nvmap_handle_put(h[i]);
+ if(h[i])
+ nvmap_handle_put(h[i]);
}
return ret;
diff --git a/drivers/video/tegra/nvmap/nvmap_common.h b/drivers/video/tegra/nvmap/nvmap_common.h
index 6da010720bb2..2a1e2b4b3c4b 100644
--- a/drivers/video/tegra/nvmap/nvmap_common.h
+++ b/drivers/video/tegra/nvmap/nvmap_common.h
@@ -23,7 +23,8 @@
extern void v7_flush_kern_cache_all(void *);
extern void v7_clean_kern_cache_all(void *);
-#define FLUSH_CLEAN_BY_SET_WAY_THRESHOLD (8 * PAGE_SIZE)
+#define FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_INNER (8 * PAGE_SIZE)
+#define FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_OUTER (1024 * 1024)
static inline void inner_flush_cache_all(void)
{
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 98b0bcc18ba5..0c12348db88e 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -290,7 +290,7 @@ int nvmap_flush_heap_block(struct nvmap_client *client,
if (prot == NVMAP_HANDLE_UNCACHEABLE || prot == NVMAP_HANDLE_WRITE_COMBINE)
goto out;
- if (len >= FLUSH_CLEAN_BY_SET_WAY_THRESHOLD) {
+ if (len >= FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_INNER) {
inner_flush_cache_all();
if (prot != NVMAP_HANDLE_INNER_CACHEABLE)
outer_flush_range(block->base, block->base + len);
@@ -886,10 +886,11 @@ static void nvmap_vma_open(struct vm_area_struct *vma)
struct nvmap_vma_priv *priv;
priv = vma->vm_private_data;
-
BUG_ON(!priv);
atomic_inc(&priv->count);
+ if(priv->handle)
+ nvmap_usecount_inc(priv->handle);
}
static void nvmap_vma_close(struct vm_area_struct *vma)
@@ -898,8 +899,8 @@ static void nvmap_vma_close(struct vm_area_struct *vma)
if (priv) {
if (priv->handle) {
+ BUG_ON(priv->handle->usecount == 0);
nvmap_usecount_dec(priv->handle);
- BUG_ON(priv->handle->usecount < 0);
}
if (!atomic_dec_return(&priv->count)) {
if (priv->handle)
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
index 05046ed8ba79..4b7760b22190 100644
--- a/drivers/video/tegra/nvmap/nvmap_handle.c
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -3,7 +3,7 @@
*
* Handle allocation and freeing routines for nvmap
*
- * 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
@@ -36,6 +36,7 @@
#include <asm/cacheflush.h>
#include <asm/outercache.h>
+#include <asm/tlbflush.h>
#include <asm/pgtable.h>
#include <mach/iovmm.h>
@@ -56,7 +57,7 @@
* the kernel (i.e., not a carveout handle) includes its array of pages. to
* 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)
+#define PAGELIST_VMALLOC_MIN (PAGE_SIZE)
#ifdef CONFIG_NVMAP_PAGE_POOLS
@@ -85,8 +86,11 @@ static struct page *nvmap_page_pool_alloc_locked(struct nvmap_page_pool *pool)
{
struct page *page = NULL;
- if (pool->npages > 0)
+ if (pool->npages > 0) {
page = pool->page_array[--pool->npages];
+ atomic_dec(&page->_count);
+ BUG_ON(atomic_read(&page->_count) != 1);
+ }
return page;
}
@@ -107,7 +111,9 @@ static bool nvmap_page_pool_release_locked(struct nvmap_page_pool *pool,
{
int ret = false;
+ BUG_ON(atomic_read(&page->_count) != 1);
if (enable_pp && pool->npages < pool->max_pages) {
+ atomic_inc(&page->_count);
pool->page_array[pool->npages++] = page;
ret = true;
}
@@ -134,6 +140,7 @@ static int nvmap_page_pool_get_available_count(struct nvmap_page_pool *pool)
static int nvmap_page_pool_free(struct nvmap_page_pool *pool, int nr_free)
{
+ int err;
int i = nr_free;
int idx = 0;
struct page *page;
@@ -149,8 +156,12 @@ static int nvmap_page_pool_free(struct nvmap_page_pool *pool, int nr_free)
i--;
}
- if (idx)
- set_pages_array_wb(pool->shrink_array, idx);
+ if (idx) {
+ /* This op should never fail. */
+ err = set_pages_array_wb(pool->shrink_array, idx);
+ BUG_ON(err);
+ }
+
while (idx--)
__free_page(pool->shrink_array[idx]);
nvmap_page_pool_unlock(pool);
@@ -367,8 +378,9 @@ POOL_SIZE_MOUDLE_PARAM_CB(wb, NVMAP_HANDLE_CACHEABLE);
int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
{
- struct page *page;
int i;
+ int err;
+ struct page *page;
static int reg = 1;
struct sysinfo info;
int highmem_pages = 0;
@@ -431,7 +443,8 @@ int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
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);
+ err = (*s_cpa[flags])(pool->page_array, pool->npages);
+ BUG_ON(err);
nvmap_page_pool_unlock(pool);
return 0;
fail:
@@ -444,7 +457,7 @@ fail:
static inline void *altalloc(size_t len)
{
- if (len >= PAGELIST_VMALLOC_MIN)
+ if (len > PAGELIST_VMALLOC_MIN)
return vmalloc(len);
else
return kmalloc(len, GFP_KERNEL);
@@ -455,7 +468,7 @@ static inline void altfree(void *ptr, size_t len)
if (!ptr)
return;
- if (len >= PAGELIST_VMALLOC_MIN)
+ if (len > PAGELIST_VMALLOC_MIN)
vfree(ptr);
else
kfree(ptr);
@@ -463,6 +476,7 @@ static inline void altfree(void *ptr, size_t len)
void _nvmap_handle_free(struct nvmap_handle *h)
{
+ int err;
struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
unsigned int i, nr_page, page_index = 0;
#ifdef CONFIG_NVMAP_PAGE_POOLS
@@ -506,9 +520,12 @@ void _nvmap_handle_free(struct nvmap_handle *h)
/* Restore page attributes. */
if (h->flags == NVMAP_HANDLE_WRITE_COMBINE ||
h->flags == NVMAP_HANDLE_UNCACHEABLE ||
- h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
- set_pages_array_wb(&h->pgalloc.pages[page_index],
+ h->flags == NVMAP_HANDLE_INNER_CACHEABLE) {
+ /* This op should never fail. */
+ err = set_pages_array_wb(&h->pgalloc.pages[page_index],
nr_page - page_index);
+ BUG_ON(err);
+ }
skip_attr_restore:
if (h->pgalloc.area)
@@ -546,6 +563,7 @@ static struct page *nvmap_alloc_pages_exact(gfp_t gfp, size_t size)
static int handle_page_alloc(struct nvmap_client *client,
struct nvmap_handle *h, bool contiguous)
{
+ int err = 0;
size_t size = PAGE_ALIGN(h->size);
unsigned int nr_page = size >> PAGE_SHIFT;
pgprot_t prot;
@@ -555,6 +573,17 @@ static int handle_page_alloc(struct nvmap_client *client,
struct nvmap_page_pool *pool = NULL;
struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
#endif
+ gfp_t gfp = GFP_NVMAP;
+ unsigned long kaddr, paddr;
+ pte_t **pte = NULL;
+
+ if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES) {
+ gfp |= __GFP_ZERO;
+ prot = nvmap_pgprot(h, pgprot_kernel);
+ pte = nvmap_alloc_pte(client->dev, (void **)&kaddr);
+ if (IS_ERR(pte))
+ return -ENOMEM;
+ }
pages = altalloc(nr_page * sizeof(*pages));
if (!pages)
@@ -565,7 +594,7 @@ static int handle_page_alloc(struct nvmap_client *client,
h->pgalloc.area = NULL;
if (contiguous) {
struct page *page;
- page = nvmap_alloc_pages_exact(GFP_NVMAP, size);
+ page = nvmap_alloc_pages_exact(gfp, size);
if (!page)
goto fail;
@@ -582,12 +611,29 @@ static int handle_page_alloc(struct nvmap_client *client,
pages[i] = nvmap_page_pool_alloc(pool);
if (!pages[i])
break;
+ if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES) {
+ /*
+ * Just memset low mem pages; they will for
+ * sure have a virtual address. Otherwise, build
+ * a mapping for the page in the kernel.
+ */
+ if (!PageHighMem(pages[i])) {
+ memset(page_address(pages[i]), 0,
+ PAGE_SIZE);
+ } else {
+ paddr = page_to_phys(pages[i]);
+ set_pte_at(&init_mm, kaddr, *pte,
+ pfn_pte(__phys_to_pfn(paddr),
+ prot));
+ flush_tlb_kernel_page(kaddr);
+ memset((char *)kaddr, 0, PAGE_SIZE);
+ }
+ }
page_index++;
}
#endif
for (; i < nr_page; i++) {
- pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP,
- PAGE_SIZE);
+ pages[i] = nvmap_alloc_pages_exact(gfp, PAGE_SIZE);
if (!pages[i])
goto fail;
}
@@ -608,16 +654,21 @@ static int handle_page_alloc(struct nvmap_client *client,
/* Update the pages mapping in kernel page table. */
if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
- set_pages_array_wc(&pages[page_index],
- nr_page - page_index);
+ err = set_pages_array_wc(&pages[page_index],
+ nr_page - page_index);
else if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
- set_pages_array_uc(&pages[page_index],
- nr_page - page_index);
+ err = set_pages_array_uc(&pages[page_index],
+ nr_page - page_index);
else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
- set_pages_array_iwb(&pages[page_index],
- nr_page - page_index);
+ err = set_pages_array_iwb(&pages[page_index],
+ nr_page - page_index);
+
+ if (err)
+ goto fail;
skip_attr_change:
+ if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES)
+ nvmap_free_pte(client->dev, pte);
h->size = size;
h->pgalloc.pages = pages;
h->pgalloc.contig = contiguous;
@@ -625,10 +676,12 @@ skip_attr_change:
return 0;
fail:
- while (i--) {
- set_pages_array_wb(&pages[i], 1);
+ if (h->userflags & NVMAP_HANDLE_ZEROED_PAGES)
+ nvmap_free_pte(client->dev, pte);
+ err = set_pages_array_wb(pages, i);
+ BUG_ON(err);
+ while (i--)
__free_page(pages[i]);
- }
altfree(pages, nr_page * sizeof(*pages));
wmb();
return -ENOMEM;
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.c b/drivers/video/tegra/nvmap/nvmap_heap.c
index a6fe78c42f87..738ba26232d3 100644
--- a/drivers/video/tegra/nvmap/nvmap_heap.c
+++ b/drivers/video/tegra/nvmap/nvmap_heap.c
@@ -3,7 +3,7 @@
*
* GPU heap allocator.
*
- * 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
@@ -420,6 +420,9 @@ static struct nvmap_heap_block *do_heap_alloc(struct nvmap_heap *heap,
list_for_each_entry(i, &heap->free_list, free_list) {
size_t fix_size;
fix_base = ALIGN(i->block.base, align);
+ if(!fix_base || fix_base >= i->block.base + i->size)
+ continue;
+
fix_size = i->size - (fix_base - i->block.base);
/* needed for compaction. relocated chunk
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
index 44f00d2951a0..da974b2c6846 100644
--- a/drivers/video/tegra/nvmap/nvmap_ioctl.c
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -3,7 +3,7 @@
*
* User-space interface to nvmap
*
- * 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
@@ -65,10 +65,10 @@ int nvmap_ioctl_pinop(struct file *filp, bool is_pin, void __user *arg)
return -EINVAL;
if (op.count > 1) {
- size_t bytes = op.count * sizeof(unsigned long *);
+ size_t bytes = op.count * sizeof(*refs); /* kcalloc below will catch overflow. */
if (op.count > ARRAY_SIZE(on_stack))
- refs = kmalloc(op.count * sizeof(*refs), GFP_KERNEL);
+ refs = kcalloc(op.count, sizeof(*refs), GFP_KERNEL);
else
refs = on_stack;
@@ -175,6 +175,9 @@ int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
/* user-space handles are aligned to page boundaries, to prevent
* data leakage. */
op.align = max_t(size_t, op.align, PAGE_SIZE);
+#if defined(CONFIG_NVMAP_FORCE_ZEROED_USER_PAGES)
+ op.flags |= NVMAP_HANDLE_ZEROED_PAGES;
+#endif
return nvmap_alloc_handle_id(client, op.handle, op.heap_mask,
op.align, op.flags);
@@ -236,6 +239,11 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg)
if (!h)
return -EPERM;
+ if(!h->alloc) {
+ nvmap_handle_put(h);
+ return -EFAULT;
+ }
+
trace_nvmap_map_into_caller_ptr(client, h, op.offset,
op.length, op.flags);
down_read(&current->mm->mmap_sem);
@@ -251,7 +259,7 @@ int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg)
goto out;
}
- if ((op.offset + op.length) > h->size) {
+ if (op.offset > h->size || (op.offset + op.length) > h->size) {
err = -EADDRNOTAVAIL;
goto out;
}
@@ -542,14 +550,32 @@ static void heap_page_cache_maint(struct nvmap_client *client,
}
}
+static bool fast_cache_maint_outer(unsigned long start,
+ unsigned long end, unsigned int op)
+{
+ bool result = false;
+#if defined(CONFIG_NVMAP_OUTER_CACHE_MAINT_BY_SET_WAYS)
+ if (end - start >= FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_OUTER) {
+ if (op == NVMAP_CACHE_OP_WB_INV) {
+ outer_flush_all();
+ result = true;
+ }
+ if (op == NVMAP_CACHE_OP_WB) {
+ outer_clean_all();
+ result = true;
+ }
+ }
+#endif
+ return result;
+}
+
static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
unsigned long start, unsigned long end, unsigned int op)
{
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))
+ ((end - start) < FLUSH_CLEAN_BY_SET_WAY_THRESHOLD_INNER))
goto out;
if (op == NVMAP_CACHE_OP_WB_INV)
@@ -557,13 +583,19 @@ static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h
else if (op == NVMAP_CACHE_OP_WB)
inner_clean_cache_all();
- if (h->heap_pgalloc && (h->flags != NVMAP_HANDLE_INNER_CACHEABLE)) {
- heap_page_cache_maint(client, h, start, end, op,
- false, true, NULL, 0, 0);
- } else if (h->flags != NVMAP_HANDLE_INNER_CACHEABLE) {
- start += h->carveout->base;
- end += h->carveout->base;
- outer_cache_maint(op, start, end - start);
+ /* outer maintenance */
+ if (h->flags != NVMAP_HANDLE_INNER_CACHEABLE ) {
+ if(!fast_cache_maint_outer(start, end, op))
+ {
+ if (h->heap_pgalloc) {
+ heap_page_cache_maint(client, h, start,
+ end, op, false, true, NULL, 0, 0);
+ } else {
+ start += h->carveout->base;
+ end += h->carveout->base;
+ outer_cache_maint(op, start, end - start);
+ }
+ }
}
ret = true;
out:
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 96499dce0b94..1f05328a7013 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -11,4 +11,5 @@ obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
+CFLAGS_tegra_w1.o = -Werror
obj-$(CONFIG_W1_MASTER_TEGRA) += tegra_w1.o
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index dd35599a2612..9c6cc30bb905 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
+CFLAGS_tegra_wdt.o = -Werror
obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index 0d8373efd3f1..1bcd726ebbd6 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -330,11 +330,11 @@ 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, *res_int_base;
+ struct resource *res_src, *res_wdt, *res_irq;
+ struct resource *res_int_base = NULL;
struct tegra_wdt *wdt;
u32 src;
int ret = 0;
- u32 val = 0;
if (pdev->id < -1 && pdev->id > 3) {
dev_err(&pdev->dev, "only IDs 3:0 supported\n");
@@ -469,6 +469,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE
/* Init and enable watchdog on WDT0 with timer 8 during probe */
if (!(pdev->id)) {
+ u32 val = 0;
wdt->status = WDT_ENABLED | WDT_ENABLED_AT_PROBE;
wdt->timeout = heartbeat;
tegra_wdt_enable(wdt);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 54d948ec49ab..d732be526293 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -66,8 +66,9 @@ enum {
/* migration should happen before other stuff but after perf */
CPU_PRI_PERF = 20,
CPU_PRI_MIGRATION = 10,
- /* prepare workqueues for other notifiers */
- CPU_PRI_WORKQUEUE = 5,
+ /* bring up workqueues before normal notifiers and down after */
+ CPU_PRI_WORKQUEUE_UP = 5,
+ CPU_PRI_WORKQUEUE_DOWN = -5,
};
#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */
diff --git a/include/linux/cpuquiet.h b/include/linux/cpuquiet.h
index fe5a03727739..5558c015bb50 100644
--- a/include/linux/cpuquiet.h
+++ b/include/linux/cpuquiet.h
@@ -30,6 +30,8 @@ struct cpuquiet_governor {
int (*start) (void);
void (*stop) (void);
int (*store_active) (unsigned int cpu, bool active);
+ void (*device_free_notification) (void);
+ void (*device_busy_notification) (void);
struct module *owner;
};
@@ -47,6 +49,8 @@ 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);
+extern void cpuquiet_device_busy(void);
+extern void cpuquiet_device_free(void);
int cpuquiet_kobject_init(struct kobject *kobj, struct kobj_type *type,
char *name);
extern unsigned int nr_cluster_ids;
diff --git a/include/linux/mfd/max77665.h b/include/linux/mfd/max77665.h
new file mode 100644
index 000000000000..380a1a4aac0d
--- /dev/null
+++ b/include/linux/mfd/max77665.h
@@ -0,0 +1,92 @@
+/*
+ * Core driver interface for MAXIM77665
+ *
+ * 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 __LINUX_MFD_MAX77665_H
+#define __LINUX_MFD_MAX77665_H
+
+#include <linux/irq.h>
+#include <linux/regmap.h>
+
+/* MAX77665 Interrups */
+enum {
+ MAX77665_IRQ_CHARGER,
+ MAX77665_IRQ_TOP_SYS,
+ MAX77665_IRQ_FLASH,
+ MAX77665_IRQ_MUIC,
+};
+
+enum {
+ MAX77665_I2C_SLAVE_PMIC,
+ MAX77665_I2C_SLAVE_MUIC,
+ MAX77665_I2C_SLAVE_HAPTIC,
+ MAX77665_I2C_SLAVE_MAX,
+};
+
+struct max77665 {
+ struct device *dev;
+ struct i2c_client *client[MAX77665_I2C_SLAVE_MAX];
+ struct regmap *regmap[MAX77665_I2C_SLAVE_MAX];
+ struct irq_chip irq_chip;
+ struct mutex irq_lock;
+ int irq_base;
+};
+
+struct max77665_platform_data {
+ int irq_base;
+};
+
+static inline int max77665_write(struct device *dev, int slv_id,
+ int reg, uint8_t val)
+{
+ struct max77665 *maxim = dev_get_drvdata(dev);
+
+ return regmap_write(maxim->regmap[slv_id], reg, val);
+}
+
+static inline int max77665_read(struct device *dev, int slv_id,
+ int reg, uint8_t *val)
+{
+ struct max77665 *maxim = dev_get_drvdata(dev);
+ unsigned int temp_val;
+ int ret;
+
+ ret = regmap_read(maxim->regmap[slv_id], reg, &temp_val);
+ if (!ret)
+ *val = temp_val;
+ return ret;
+}
+
+static inline int max77665_set_bits(struct device *dev, int slv_id,
+ int reg, uint8_t bit_num)
+{
+ struct max77665 *maxim = dev_get_drvdata(dev);
+
+ return regmap_update_bits(maxim->regmap[slv_id],
+ reg, BIT(bit_num), ~0u);
+}
+
+static inline int max77665_clr_bits(struct device *dev, int slv_id,
+ int reg, uint8_t bit_num)
+{
+ struct max77665 *maxim = dev_get_drvdata(dev);
+
+ return regmap_update_bits(maxim->regmap[slv_id],
+ reg, BIT(bit_num), 0u);
+}
+
+#endif /*__LINUX_MFD_MAX77665_H */
diff --git a/include/linux/mfd/tlv320aic3262-core.h b/include/linux/mfd/tlv320aic3262-core.h
new file mode 100644
index 000000000000..3c79ae98f860
--- /dev/null
+++ b/include/linux/mfd/tlv320aic3262-core.h
@@ -0,0 +1,237 @@
+#ifndef __MFD_AIC3262_CORE_H__
+#define __MFD_AIC3262_CORE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+enum aic3262_type {
+ TLV320AIC3262 = 0,
+};
+
+#define AIC3262_IRQ_HEADSET_DETECT 0
+#define AIC3262_IRQ_BUTTON_PRESS 1
+#define AIC3262_IRQ_DAC_DRC 2
+#define AIC3262_IRQ_AGC_NOISE 3
+#define AIC3262_IRQ_OVER_CURRENT 4
+#define AIC3262_IRQ_OVERFLOW_EVENT 5
+#define AIC3262_IRQ_SPEAKER_OVER_TEMP 6
+
+#define AIC3262_GPIO1 7
+#define AIC3262_GPIO2 8
+#define AIC3262_GPI1 9
+#define AIC3262_GPI2 10
+#define AIC3262_GPO1 11
+
+union aic326x_reg_union {
+ struct aic326x_reg {
+ u8 offset;
+ u8 page;
+ u8 book;
+ u8 reserved;
+ } aic326x_register;
+ unsigned int aic326x_register_int;
+};
+
+/**************************** ************************************/
+
+/*
+ *****************************************************************************
+ * Structures Definitions
+ *****************************************************************************
+ */
+/*
+ *----------------------------------------------------------------------------
+ * @struct aic3262_setup_data |
+ * i2c specific data setup for AIC3262.
+ * @field unsigned short |i2c_address |
+ * Unsigned short for i2c address.
+ *----------------------------------------------------------------------------
+ */
+struct aic3262_setup_data {
+ unsigned short i2c_address;
+};
+
+/* GPIO API */
+#define AIC3262_NUM_GPIO 5 /* include 2 GPI and 1 GPO pins */
+enum {
+ AIC3262_GPIO1_FUNC_DISABLED = 0,
+ AIC3262_GPIO1_FUNC_INPUT = 1,
+ AIC3262_GPIO1_FUNC_OUTPUT = 3,
+ AIC3262_GPIO1_FUNC_CLOCK_OUTPUT = 4,
+ AIC3262_GPIO1_FUNC_INT1_OUTPUT = 5,
+ AIC3262_GPIO1_FUNC_INT2_OUTPUT = 6,
+ AIC3262_GPIO1_FUNC_ADC_MOD_CLK_OUTPUT = 10,
+ AIC3262_GPIO1_FUNC_SAR_ADC_INTERRUPT = 12,
+ AIC3262_GPIO1_FUNC_ASI1_DATA_OUTPUT = 15,
+ AIC3262_GPIO1_FUNC_ASI1_WCLK = 16,
+ AIC3262_GPIO1_FUNC_ASI1_BCLK = 17,
+ AIC3262_GPIO1_FUNC_ASI2_WCLK = 18,
+ AIC3262_GPIO1_FUNC_ASI2_BCLK = 19,
+ AIC3262_GPIO1_FUNC_ASI3_WCLK = 20,
+ AIC3262_GPIO1_FUNC_ASI3_BCLK = 21
+};
+
+enum {
+ AIC3262_GPIO2_FUNC_DISABLED = 0,
+ AIC3262_GPIO2_FUNC_INPUT = 1,
+ AIC3262_GPIO2_FUNC_OUTPUT = 3,
+ AIC3262_GPIO2_FUNC_CLOCK_OUTPUT = 4,
+ AIC3262_GPIO2_FUNC_INT1_OUTPUT = 5,
+ AIC3262_GPIO2_FUNC_INT2_OUTPUT = 6,
+ AIC3262_GPIO2_FUNC_ADC_MOD_CLK_OUTPUT = 10,
+ AIC3262_GPIO2_FUNC_SAR_ADC_INTERRUPT = 12,
+ AIC3262_GPIO2_FUNC_ASI1_DATA_OUTPUT = 15,
+ AIC3262_GPIO2_FUNC_ASI1_WCLK = 16,
+ AIC3262_GPIO2_FUNC_ASI1_BCLK = 17,
+ AIC3262_GPIO2_FUNC_ASI2_WCLK = 18,
+ AIC3262_GPIO2_FUNC_ASI2_BCLK = 19,
+ AIC3262_GPIO2_FUNC_ASI3_WCLK = 20,
+ AIC3262_GPIO2_FUNC_ASI3_BCLK = 21
+};
+enum {
+ AIC3262_GPO1_FUNC_DISABLED = 0,
+ AIC3262_GPO1_FUNC_MSO_OUTPUT_FOR_SPI = 1,
+ AIC3262_GPO1_FUNC_GENERAL_PURPOSE_OUTPUT = 2,
+ AIC3262_GPO1_FUNC_CLOCK_OUTPUT = 3,
+ AIC3262_GPO1_FUNC_INT1_OUTPUT = 4,
+ AIC3262_GPO1_FUNC_INT2_OUTPUT = 5,
+ AIC3262_GPO1_FUNC_ADC_MOD_CLK_OUTPUT = 7,
+ AIC3262_GPO1_FUNC_SAR_ADC_INTERRUPT = 12,
+ AIC3262_GPO1_FUNC_ASI1_DATA_OUTPUT = 15,
+};
+/*
+ *----------------------------------------------------------------------------
+ * @struct aic3262_configs |
+ * AIC3262 initialization data which has register offset and register
+ * value.
+ * @field u8 | book_no |
+ * AIC3262 Book Number Offsets required for initialization..
+ * @field u16 | reg_offset |
+ * AIC3262 Register offsets required for initialization..
+ * @field u8 | reg_val |
+ * value to set the AIC3262 register to initialize the AIC3262.
+ *---------------------------------------------------------------------------
+ */
+struct aic3262_configs {
+ u8 book_no;
+ u16 reg_offset;
+ u8 reg_val;
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct aic3262_rate_divs |
+ * Setting up the values to get different freqencies
+ *
+ * @field u32 | mclk |
+ * Master clock
+ * @field u32 | rate |
+ * sample rate
+ * @field u8 | p_val |
+ * value of p in PLL
+ * @field u32 | pll_j |
+ * value for pll_j
+ * @field u32 | pll_d |
+ * value for pll_d
+ * @field u32 | dosr |
+ * value to store dosr
+ * @field u32 | ndac |
+ * value for ndac
+ * @field u32 | mdac |
+ * value for mdac
+ * @field u32 | aosr |
+ * value for aosr
+ * @field u32 | nadc |
+ * value for nadc
+ * @field u32 | madc |
+ * value for madc
+ * @field u32 | blck_N |
+ * value for block N
+ */
+struct aic3262 {
+ struct mutex io_lock;
+ struct mutex irq_lock;
+ enum aic3262_type type;
+ struct device *dev;
+ int (*read_dev)(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, void *dest);
+ int (*write_dev)(struct aic3262 *aic3262, unsigned int reg,
+ int bytes, const void *src);
+
+ void *control_data;
+ unsigned int irq;
+ unsigned int irq_base;
+ u8 irq_masks_cur;
+ u8 irq_masks_cache;
+ /* Used over suspend/resume */
+ bool suspended;
+ u8 book_no;
+ u8 page_no;
+};
+
+struct aic3262_gpio_setup {
+ u8 used; /* GPIO, GPI and GPO is used in the board, */
+ /* used = 1 else 0 */
+ u8 in; /* GPIO is used as input, in = 1 else in = 0 */
+ /* GPI in = 1, GPO in = 0 */
+ unsigned int in_reg; /* if GPIO is input,
+ register to write the mask. */
+ u8 in_reg_bitmask; /* bitmask for 'value' to be
+ written into in_reg */
+ u8 in_reg_shift; /* bits to shift to write 'value'
+ into in_reg */
+ u8 value; /* value to be written
+ gpio_control_reg if GPIO */
+ /* is output, in_reg if its input */
+};
+
+struct aic3262_pdata {
+ unsigned int audio_mclk1;
+ unsigned int audio_mclk2;
+ unsigned int gpio_irq; /* whether AIC3262 interrupts the host AP on */
+ /* a GPIO pin of AP */
+ unsigned int gpio_reset;/* is the codec being reset by a gpio*/
+ /* [host] pin, if yes provide the number. */
+ struct aic3262_gpio_setup *gpio;/* all gpio configuration */
+ int naudint_irq; /* audio interrupt */
+ unsigned int irq_base;
+};
+
+static inline int aic3262_request_irq(struct aic3262 *aic3262, int irq,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *name,
+ void *data)
+{
+ if (!aic3262->irq_base)
+ return -EINVAL;
+
+ return request_threaded_irq(aic3262->irq_base + irq, NULL, handler,
+ irqflags, name, data);
+}
+
+static inline int aic3262_free_irq(struct aic3262 *aic3262, int irq, void *data)
+{
+ if (!aic3262->irq_base)
+ return -EINVAL;
+
+ free_irq(aic3262->irq_base + irq, data);
+ return 0;
+}
+
+/* Device I/O API */
+int aic3262_reg_read(struct aic3262 *aic3262, unsigned int reg);
+int aic3262_reg_write(struct aic3262 *aic3262, unsigned int reg,
+ unsigned char val);
+int aic3262_set_bits(struct aic3262 *aic3262, unsigned int reg,
+ unsigned char mask, unsigned char val);
+int aic3262_bulk_read(struct aic3262 *aic3262, unsigned int reg,
+ int count, u8 *buf);
+int aic3262_bulk_write(struct aic3262 *aic3262, unsigned int reg,
+ int count, const u8 *buf);
+int aic3262_wait_bits(struct aic3262 *aic3262, unsigned int reg,
+ unsigned char mask, unsigned char val, int delay,
+ int counter);
+
+int aic3262_irq_init(struct aic3262 *aic3262);
+void aic3262_irq_exit(struct aic3262 *aic3262);
+
+#endif /* End of __MFD_AIC3262_CORE_H__ */
diff --git a/include/linux/mfd/tlv320aic3262-registers.h b/include/linux/mfd/tlv320aic3262-registers.h
new file mode 100644
index 000000000000..bdd7dfed80cd
--- /dev/null
+++ b/include/linux/mfd/tlv320aic3262-registers.h
@@ -0,0 +1,323 @@
+
+#ifndef __MFD_AIC3262_REGISTERS_H__
+#define __MFD_AIC3262_REGISTERS_H__
+
+#define MAKE_REG(book, page, offset) \
+ (unsigned int)((book << 16)|(page << 8)|offset)
+
+/* ****************** Book 0 Registers **************************************/
+
+/* ****************** Page 0 Registers **************************************/
+#define AIC3262_PAGE_SEL_REG MAKE_REG(0, 0, 0)
+#define AIC3262_RESET_REG MAKE_REG(0, 0, 1)
+#define AIC3262_REV_PG_ID MAKE_REG(0, 0, 2)
+#define AIC3262_REV_MASK (0b01110000)
+#define AIC3262_REV_SHIFT 4
+#define AIC3262_PG_MASK (0b00000111)
+#define AIC3262_PG_SHIFT 0
+#define AIC3262_DAC_ADC_CLKIN_REG MAKE_REG(0, 0, 4)
+#define AIC3262_PLL_CLKIN_REG MAKE_REG(0, 0, 5)
+#define AIC3262_PLL_CLKIN_MASK (0b00111100)
+#define AIC3262_PLL_CLKIN_SHIFT 2
+#define AIC3262_PLL_CLKIN_MCLK1 0
+#define AIC3262_PLL_CLKIN_BCLK1 1
+#define AIC3262_PLL_CLKIN_GPIO1 2
+#define AIC3262_PLL_CLKIN_DIN1 3
+#define AIC3262_PLL_CLKIN_BCLK2 4
+#define AIC3262_PLL_CLKIN_GPI1 5
+#define AIC3262_PLL_CLKIN_HF_REF_CLK 6
+#define AIC3262_PLL_CLKIN_GPIO2 7
+#define AIC3262_PLL_CLKIN_GPI2 8
+#define AIC3262_PLL_CLKIN_MCLK2 9
+#define AIC3262_CLK_VAL_MASK 0x7f
+#define AIC3262_PLL_CLK_RANGE_REG MAKE_REG(0, 0, 5)
+#define AIC3262_PLL_PR_POW_REG MAKE_REG(0, 0, 6)
+#define AIC3262_PLL_PVAL_MASK 0x70
+#define AIC3262_PLL_RVAL_MASK 0x0F
+
+#define AIC3262_ENABLE_CLK_MASK 0x80
+#define AIC3262_ENABLE_CLK 0x80
+
+#define AIC3262_PLL_J_REG MAKE_REG(0, 0, 7)
+#define AIC3262_JVAL_MASK 0x3f
+#define AIC3262_PLL_D_MSB MAKE_REG(0, 0, 8)
+#define AIC3262_DVAL_MSB_MASK 0xf
+#define AIC3262_DVAL_LSB_MASK 0xff
+#define AIC3262_PLL_D_LSB MAKE_REG(0, 0, 9)
+#define AIC3262_PLL_CKIN_DIV MAKE_REG(0, 0, 10)
+
+#define AIC3262_NDAC_DIV_POW_REG MAKE_REG(0, 0, 11)
+#define AIC3262_MDAC_DIV_POW_REG MAKE_REG(0, 0, 12)
+#define AIC3262_DOSR_MSB_REG MAKE_REG(0, 0, 13)
+#define AIC3262_DOSR_MSB_MASK 0x3
+#define AIC3262_DOSR_LSB_REG MAKE_REG(0, 0, 14)
+#define AIC3262_DOSR_LSB_MASK 0xFF
+
+#define AIC3262_NADC_DIV_POW_REG MAKE_REG(0, 0, 18)
+#define AIC3262_MADC_DIV_POW_REG MAKE_REG(0, 0, 19)
+#define AIC3262_AOSR_REG MAKE_REG(0, 0, 20)
+#define AIC3262_CLKOUT_MUX MAKE_REG(0, 0, 21)
+#define AIC3262_CLKOUT_MDIV_VAL MAKE_REG(0, 0, 22)
+#define AIC3262_TIMER_REG MAKE_REG(0, 0, 23)
+
+#define AIC3262_LF_CLK_CNTL MAKE_REG(0, 0, 24)
+#define AIC3262_HF_CLK_CNTL_R1 MAKE_REG(0, 0, 25)
+#define AIC3262_HF_CLK_CNTL_R2 MAKE_REG(0, 0, 26)
+#define AIC3262_HF_CLK_CNTL_R3 MAKE_REG(0, 0, 27)
+#define AIC3262_HF_CLK_CNTL_R4 MAKE_REG(0, 0, 28)
+#define AIC3262_HF_CLK_TRIM_R1 MAKE_REG(0, 0, 29)
+#define AIC3262_HF_CLK_TRIM_R2 MAKE_REG(0, 0, 30)
+#define AIC3262_HF_CLK_TRIM_R3 MAKE_REG(0, 0, 31)
+#define AIC3262_HF_CLK_TRIM_R4 MAKE_REG(0, 0, 32)
+#define AIC3262_LDAC_POWER_MASK 0x80
+#define AIC3262_RDAC_POWER_MASK 0x08
+#define AIC3262_DAC_POWER_MASK 0x88
+#define AIC3262_DAC_FLAG MAKE_REG(0, 0, 37)
+#define AIC3262_LADC_POWER_MASK 0x40
+#define AIC3262_RADC_POWER_MASK 0x04
+#define AIC3262_ADC_POWER_MASK 0x44
+#define AIC3262_ADC_FLAG MAKE_REG(0, 0, 36)
+#define AIC3262_JACK_WITH_STEREO_HS (0b00000010)
+#define AIC3262_JACK_WITH_MIC (0b00110000)
+#define AIC3262_HEADSET_NOT_INSERTED (0b00000011)
+
+#define AIC3262_INT_STICKY_FLAG1 MAKE_REG(0, 0, 42)
+#define AIC3262_LEFT_DAC_OVERFLOW_INT 0x80
+#define AIC3262_RIGHT_DAC_OVERFLOW_INT 0x40
+#define AIC3262_MINIDSP_D_BARREL_SHIFT_OVERFLOW_INT 0x20
+#define AIC3262_LEFT_ADC_OVERFLOW_INT 0x08
+#define AIC3262_RIGHT_ADC_OVERFLOW_INT 0x04
+#define AIC3262_MINIDSP_A_BARREL_SHIFT_OVERFLOW_INT 0x02
+#define AIC3262_INT_STICKY_FLAG2 MAKE_REG(0, 0, 44)
+#define AIC3262_LEFT_OUTPUT_DRIVER_OVERCURRENT_INT 0x80
+#define AIC3262_RIGHT_OUTPUT_DRIVER_OVERCURRENT_INT 0x40
+#define AIC3262_BUTTON_PRESS_INT 0x20
+#define AIC3262_HEADSET_PLUG_UNPLUG_INT 0x10
+#define AIC3262_LEFT_DRC_THRES_INT 0x08
+#define AIC3262_RIGHT_DRC_THRES_INT 0x04
+#define AIC3262_MINIDSP_D_STD_INT 0x02
+#define AIC3262_RIGHT_DRC_AUX_INT 0x01
+#define AIC3262_INT_STICKY_FLAG3 MAKE_REG(0, 0, 45)
+#define AIC3262_SPK_OVER_CURRENT_INT 0x80
+#define AIC3262_LEFT_AGC_NOISE_INT 0x40
+#define AIC3262_RIGHT_AGC_NOISE_INT 0x20
+#define AIC3262_INT1_CNTL MAKE_REG(0, 0, 48)
+#define AIC3262_HEADSET_IN_MASK 0x80
+#define AIC3262_BUTTON_PRESS_MASK 0x40
+#define AIC3262_DAC_DRC_THRES_MASK 0x20
+#define AIC3262_AGC_NOISE_MASK 0x10
+#define AIC3262_OVER_CURRENT_MASK 0x08
+#define AIC3262_OVERFLOW_MASK 0x04
+#define AIC3262_SPK_OVERCURRENT_MASK 0x02
+#define AIC3262_INT2_CNTL MAKE_REG(0, 0, 49)
+#define AIC3262_INT_FMT MAKE_REG(0, 0, 51)
+
+#define AIC3262_DAC_PRB MAKE_REG(0, 0, 60)
+#define AIC3262_ADC_PRB MAKE_REG(0, 0, 61)
+#define AIC3262_PASI_DAC_DP_SETUP MAKE_REG(0, 0, 63)
+
+#define AIC3262_DAC_MVOL_CONF MAKE_REG(0, 0, 64)
+#define AIC3262_DAC_LR_MUTE_MASK 0xc
+#define AIC3262_DAC_LR_MUTE 0xc
+
+#define AIC3262_DAC_LVOL MAKE_REG(0, 0, 65)
+#define AIC3262_DAC_RVOL MAKE_REG(0, 0, 66)
+#define AIC3262_HP_DETECT MAKE_REG(0, 0, 67)
+#define AIC3262_DRC_CNTL_R1 MAKE_REG(0, 0, 68)
+#define AIC3262_DRC_CNTL_R2 MAKE_REG(0, 0, 69)
+#define AIC3262_DRC_CNTL_R3 MAKE_REG(0, 0, 70)
+#define AIC3262_BEEP_CNTL_R1 MAKE_REG(0, 0, 71)
+#define AIC3262_BEEP_CNTL_R2 MAKE_REG(0, 0, 72)
+
+#define AIC3262_ADC_CHANNEL_POW MAKE_REG(0, 0, 81)
+#define AIC3262_ADC_FINE_GAIN MAKE_REG(0, 0, 82)
+#define AIC3262_LADC_VOL MAKE_REG(0, 0, 83)
+#define AIC3262_RADC_VOL MAKE_REG(0, 0, 84)
+#define AIC3262_ADC_PHASE MAKE_REG(0, 0, 85)
+
+#define AIC3262_LAGC_CNTL MAKE_REG(0, 0, 86)
+#define AIC3262_LAGC_CNTL_R2 MAKE_REG(0, 0, 87)
+#define AIC3262_LAGC_CNTL_R3 MAKE_REG(0, 0, 88)
+#define AIC3262_LAGC_CNTL_R4 MAKE_REG(0, 0, 89)
+#define AIC3262_LAGC_CNTL_R5 MAKE_REG(0, 0, 90)
+#define AIC3262_LAGC_CNTL_R6 MAKE_REG(0, 0, 91)
+#define AIC3262_LAGC_CNTL_R7 MAKE_REG(0, 0, 92)
+#define AIC3262_LAGC_CNTL_R8 MAKE_REG(0, 0, 93)
+
+#define AIC3262_RAGC_CNTL MAKE_REG(0, 0, 94)
+#define AIC3262_RAGC_CNTL_R2 MAKE_REG(0, 0, 95)
+#define AIC3262_RAGC_CNTL_R3 MAKE_REG(0, 0, 96)
+#define AIC3262_RAGC_CNTL_R4 MAKE_REG(0, 0, 97)
+#define AIC3262_RAGC_CNTL_R5 MAKE_REG(0, 0, 98)
+#define AIC3262_RAGC_CNTL_R6 MAKE_REG(0, 0, 99)
+#define AIC3262_RAGC_CNTL_R7 MAKE_REG(0, 0, 100)
+#define AIC3262_RAGC_CNTL_R8 MAKE_REG(0, 0, 101)
+#define AIC3262_MINIDSP_ACCESS_CTRL MAKE_REG(0, 0, 121)
+/* ****************** Page 1 Registers **************************************/
+#define AIC3262_PAGE_1 128
+
+#define AIC3262_POWER_CONF MAKE_REG(0, 1, 1)
+
+#define AIC3262_AVDD_TO_DVDD_MASK (0b00001000)
+#define AIC3262_AVDD_TO_DVDD 0x8
+#define AIC3262_EXT_ANALOG_SUPPLY_MASK (0b00000100)
+#define AIC3262_EXT_ANALOG_SUPPLY_OFF 0x4
+
+#define AIC3262_LDAC_PTM MAKE_REG(0, 1, 3)
+#define AIC3262_RDAC_PTM MAKE_REG(0, 1, 4)
+#define AIC3262_CM_REG MAKE_REG(0, 1, 8)
+#define AIC3262_HP_CTL MAKE_REG(0, 1, 9)
+#define AIC3262_HP_DEPOP MAKE_REG(0, 1, 11)
+#define AIC3262_RECV_DEPOP MAKE_REG(0, 1, 12)
+#define AIC3262_MA_CNTL MAKE_REG(0, 1, 17)
+#define AIC3262_LADC_PGA_MAL_VOL MAKE_REG(0, 1, 18)
+#define AIC3262_RADC_PGA_MAR_VOL MAKE_REG(0, 1, 19)
+
+#define AIC3262_LINE_AMP_CNTL_R1 MAKE_REG(0, 1, 22)
+#define AIC3262_LINE_AMP_CNTL_R2 MAKE_REG(0, 1, 23)
+
+#define AIC3262_HP_AMP_CNTL_R1 MAKE_REG(0, 1, 27)
+#define AIC3262_HP_AMP_CNTL_R2 MAKE_REG(0, 1, 28)
+#define AIC3262_HP_AMP_CNTL_R3 MAKE_REG(0, 1, 29)
+
+#define AIC3262_HPL_VOL MAKE_REG(0, 1, 31)
+#define AIC3262_HPR_VOL MAKE_REG(0, 1, 32)
+#define AIC3262_INT1_SEL_L MAKE_REG(0, 1, 34)
+#define AIC3262_CHARGE_PUMP_CNTL MAKE_REG(0, 1, 35)
+#define AIC3262_RAMP_CNTL_R1 MAKE_REG(0, 1, 36)
+#define AIC3262_RAMP_CNTL_R2 MAKE_REG(0, 1, 37)
+#define AIC3262_IN1L_SEL_RM MAKE_REG(0, 1, 38)
+#define AIC3262_IN1R_SEL_RM MAKE_REG(0, 1, 39)
+#define AIC3262_REC_AMP_CNTL_R5 MAKE_REG(0, 1, 40)
+#define AIC3262_RAMPR_VOL MAKE_REG(0, 1, 41)
+#define AIC3262_RAMP_TIME_CNTL MAKE_REG(0, 1, 42)
+#define AIC3262_SPK_AMP_CNTL_R1 MAKE_REG(0, 1, 45)
+#define AIC3262_SPK_AMP_CNTL_R2 MAKE_REG(0, 1, 46)
+#define AIC3262_SPK_AMP_CNTL_R3 MAKE_REG(0, 1, 47)
+#define AIC3262_SPK_AMP_CNTL_R4 MAKE_REG(0, 1, 48)
+#define AIC3262_MIC_BIAS_CNTL MAKE_REG(0, 1, 51)
+
+#define AIC3262_LMIC_PGA_PIN MAKE_REG(0, 1, 52)
+#define AIC3262_LMIC_PGA_PM_IN4 MAKE_REG(0, 1, 53)
+#define AIC3262_LMIC_PGA_MIN MAKE_REG(0, 1, 54)
+#define AIC3262_RMIC_PGA_PIN MAKE_REG(0, 1, 55)
+#define AIC3262_RMIC_PGA_PM_IN4 MAKE_REG(0, 1, 56)
+#define AIC3262_RMIC_PGA_MIN MAKE_REG(0, 1, 57)
+#define AIC3262_HP_FLAG MAKE_REG(0, 1, 66)
+#define AIC3262_SPKL_POWER_MASK 0x2
+#define AIC3262_SPKR_POWER_MASK 0x1
+#define AIC3262_HPL_POWER_MASK 0x20
+#define AIC3262_HPR_POWER_MASK 0x10
+/* MIC PGA Gain Registers */
+#define AIC3262_MICL_PGA MAKE_REG(0, 1, 59)
+#define AIC3262_MICR_PGA MAKE_REG(0, 1, 60)
+#define AIC3262_HEADSET_TUNING1_REG MAKE_REG(0, 1, 119)
+#define AIC3262_HEADSET_DETECTOR_PULSE_MASK (0b11000000)
+#define AIC3262_HEADSET_DETECTOR_PULSE_RESET (0b10000000)
+#define AIC3262_MIC_PWR_DLY MAKE_REG(0, 1, 121)
+#define AIC3262_REF_PWR_DLY MAKE_REG(0, 1, 122)
+#define AIC3262_CHIP_REF_PWR_ON_MASK 0x4
+#define AIC3262_CHIP_REF_PWR_ON 0x4
+/* ****************** Page 4 Registers **************************************/
+#define AIC3262_PAGE_4 512
+#define AIC3262_ASI1_BUS_FMT MAKE_REG(0, 4, 1)
+#define AIC3262_ASI_SELECTION_MASK (0b11100000)
+#define AIC3262_ASI_DATA_WORD_LENGTH_MASK (0b00011000)
+#define AIC3262_ASI_BCLK_N_MASK (0b01111111)
+#define AIC3262_ASI1_LCH_OFFSET MAKE_REG(0, 4, 2)
+#define AIC3262_ASI1_RCH_OFFSET MAKE_REG(0, 4, 3)
+#define AIC3262_ASI1_CHNL_SETUP MAKE_REG(0, 4, 4)
+#define AIC3262_ASI1_MULTI_CH_SETUP_R1 MAKE_REG(0, 4, 5)
+#define AIC3262_ASI1_MULTI_CH_SETUP_R2 MAKE_REG(0, 4, 6)
+#define AIC3262_ASI1_ADC_INPUT_CNTL MAKE_REG(0, 4, 7)
+#define AIC3262_ASI1_DAC_OUT_CNTL MAKE_REG(0, 4, 8)
+#define AIC3262_ASI1_ADC_OUT_TRISTATE MAKE_REG(0, 4, 9)
+#define AIC3262_ASI1_BWCLK_CNTL_REG MAKE_REG(0, 4, 10)
+#define AIC3262_ASI1_BCLK_N_CNTL MAKE_REG(0, 4, 11)
+#define AIC3262_ASI1_BCLK_N MAKE_REG(0, 4, 12)
+#define AIC3262_ASI1_WCLK_N MAKE_REG(0, 4, 13)
+#define AIC3262_ASI1_BWCLK_OUT_CNTL MAKE_REG(0, 4, 14)
+#define AIC3262_ASI1_DOUT_CNTL MAKE_REG(0, 4, 15)
+#define AIC3262_ASI2_BUS_FMT MAKE_REG(0, 4, 17)
+#define AIC3262_ASI2_LCH_OFFSET MAKE_REG(0, 4, 18)
+#define AIC3262_ASI2_ADC_INPUT_CNTL MAKE_REG(0, 4, 23)
+#define AIC3262_ASI2_DAC_OUT_CNTL MAKE_REG(0, 4, 24)
+#define AIC3262_ASI2_BWCLK_CNTL_REG MAKE_REG(0, 4, 26)
+#define AIC3262_ASI2_BCLK_N_CNTL MAKE_REG(0, 4, 27)
+#define AIC3262_ASI2_BCLK_N MAKE_REG(0, 4, 28)
+#define AIC3262_ASI2_WCLK_N MAKE_REG(0, 4, 29)
+#define AIC3262_ASI2_BWCLK_OUT_CNTL MAKE_REG(0, 4, 30)
+#define AIC3262_ASI2_DOUT_CNTL MAKE_REG(0, 4, 31)
+#define AIC3262_ASI3_BUS_FMT MAKE_REG(0, 4, 33)
+#define AIC3262_ASI3_LCH_OFFSET MAKE_REG(0, 4, 34)
+#define AIC3262_ASI3_ADC_INPUT_CNTL MAKE_REG(0, 4, 39)
+#define AIC3262_ASI3_DAC_OUT_CNTL MAKE_REG(0, 4, 40)
+#define AIC3262_ASI3_BWCLK_CNTL_REG MAKE_REG(0, 4, 42)
+#define AIC3262_ASI3_BCLK_N_CNTL MAKE_REG(0, 4, 43)
+#define AIC3262_ASI3_BCLK_N MAKE_REG(0, 4, 44)
+#define AIC3262_ASI3_WCLK_N MAKE_REG(0, 4, 45)
+#define AIC3262_ASI3_BWCLK_OUT_CNTL MAKE_REG(0, 4, 46)
+#define AIC3262_ASI3_DOUT_CNTL MAKE_REG(0, 4, 47)
+#define AIC3262_GPIO1_IO_CNTL MAKE_REG(0, 4, 86)
+#define AIC3262_GPIO_D6_D2 (0b01111100)
+#define AIC3262_GPIO_D2_SHIFT (2)
+#define AIC3262_GPIO_D1_SHIFT (1)
+#define AIC3262_GPIO_D4_SHIFT (4)
+#define AIC3262_GPIO2_IO_CNTL MAKE_REG(0, 4, 87)
+#define AIC3262_GPI1_EN MAKE_REG(0, 4, 91)
+#define AIC3262_GPI1_D2_D1 (0b00000110)
+#define AIC3262_GPI2_D5_D4 (0b00110000)
+#define AIC3262_GPI2_EN MAKE_REG(0, 4, 92)
+#define AIC3262_GPO1_OUT_CNTL MAKE_REG(0, 4, 96)
+#define AIC3262_GPO1_D4_D1 (0b00011110)
+#define AIC3262_DMIC_INPUT_CNTL MAKE_REG(0, 4, 101)
+#define AIC3262_DMIC_CONFIGURE_MASK (0b00011111)
+#define AIC3262_DMIC_CONFIGURE_SHIFT (0)
+#define AIC3262_DMIC_GPI1_LEFT_GPI1_RIGHT (0)
+#define AIC3262_DMIC_GPI2_LEFT_GPI2_RIGHT (1)
+#define AIC3262_DMIC_DIN1_LEFT_DIN1_RIGHT (2)
+#define AIC3262_DMIC_DIN2_LEFT_DIN2_RIGHT (3)
+#define AIC3262_DMIC_GPI01_LEFT_GPI01_RIGHT (4)
+#define AIC3262_DMIC_GPI02_LEFT_GPI02_RIGHT (5)
+#define AIC3262_DMIC_MCLK2_LEFT_MCLK2_RIGHT (6)
+#define AIC3262_DMIC_GPI1_LEFT_GPI2_RIGHT (7)
+#define AIC3262_DMIC_GPI1_LEFT_DIN1_RIGHT (8)
+#define AIC3262_DMIC_GPI1_LEFT_DIN2_RIGHT (9)
+#define AIC3262_DMIC_GPI1_LEFT_GPIO1_RIGHT (10)
+#define AIC3262_DMIC_GPI1_LEFT_GPIO2_RIGHT (11)
+#define AIC3262_DMIC_GPI1_LEFT_MCLK2_RIGHT (12)
+#define AIC3262_DMIC_GPI2_LEFT_DIN1_RIGHT (13)
+#define AIC3262_DMIC_GPI2_LEFT_DIN2_RIGHT (14)
+#define AIC3262_DMIC_GPI2_LEFT_GPIO1_RIGHT (15)
+#define AIC3262_DMIC_GPI2_LEFT_GPIO2_RIGHT (16)
+#define AIC3262_DMIC_GPI2_LEFT_MCLK2_RIGHT (17)
+#define AIC3262_DMIC_DIN1_LEFT_DIN2_RIGHT (18)
+#define AIC3262_DMIC_DIN1_LEFT_GPIO1_RIGHT (19)
+#define AIC3262_DMIC_DIN1_LEFT_GPIO2_RIGHT (20)
+#define AIC3262_DMIC_DIN1_LEFT_MCLK2_RIGHT (21)
+#define AIC3262_DMIC_DIN2_LEFT_GPIO1_RIGHT (22)
+#define AIC3262_DMIC_DIN2_LEFT_GPIO2_RIGHT (23)
+#define AIC3262_DMIC_DIN2_LEFT_MCLK2_RIGHT (24)
+#define AIC3262_DMIC_GPI01_LEFT_GPI02_RIGHT (25)
+#define AIC3262_DMIC_GPI01_LEFT_MCLK2_RIGHT (26)
+#define AIC3262_DMIC_GPI02_LEFT_MCLK2_RIGHT (27)
+#define AIC3262_MINIDSP_DATA_PORT_CNTL MAKE_REG(0, 4, 118)
+
+#define AIC3262_DAC_ASI_LR_UNMUTE_MASK 0x50
+#define AIC3262_DAC_ASI_LR_UNMUTE 0x50
+#define AIC3262_WCLK_BCLK_MASTER_MASK (0b00100110)
+#define AIC3262_WCLK_MASTER_MASK (0b00100000)
+#define AIC3262_BCLK_MASTER_MASK (0b00000100)
+#define AIC3262_BCLK_OFFSET_MASK (0b11111111)
+#define AIC3262_ASI_INTERFACE_MASK (0b11100000)
+#define AIC3262_WCLK_OUT_MASK (0b00100000)
+#define AIC3262_BCLK_OUT_MASK (0b00000100)
+#define AIC3262_BCLK_INV_MASK (0b00000010)
+
+#define AIC3262_ADC_ADAPTIVE_CRAM_REG MAKE_REG(40, 0, 1)
+#define AIC3262_DAC_ADAPTIVE_BANK1_REG MAKE_REG(80, 0, 1)
+#define AIC3262_DAC_ADAPTIVE_BANK2_REG MAKE_REG(82, 0, 1)
+#define AIC3262_ADC_DATAPATH_SETUP MAKE_REG(0, 0, 81)
+#define AIC3262_DAC_DATAPATH_SETUP MAKE_REG(0, 0, 63)
+
+#endif
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h
index 511ced59ef1a..7ae86b956710 100644
--- a/include/linux/mfd/tps65090.h
+++ b/include/linux/mfd/tps65090.h
@@ -1,5 +1,4 @@
/*
- * include/linux/mfd/tps65090.h
* Core driver interface for TI TPS65090 PMIC family
*
* Copyright (C) 2012 NVIDIA Corporation
@@ -23,31 +22,60 @@
#ifndef __LINUX_MFD_TPS65090_H
#define __LINUX_MFD_TPS65090_H
-#include <linux/rtc.h>
+#include <linux/irq.h>
+#include <linux/regmap.h>
-struct tps65090_subdev_info {
- int id;
- const char *name;
- void *platform_data;
+struct tps65090 {
+ struct device *dev;
+ struct regmap *rmap;
+ struct irq_chip irq_chip;
+ struct mutex irq_lock;
+ int irq_base;
};
struct tps65090_platform_data {
int irq_base;
- int num_subdevs;
- struct tps65090_subdev_info *subdevs;
+ struct tps65090_regulator_platform_data **reg_pdata;
+ int num_reg_pdata;
};
/*
* NOTE: the functions below are not intended for use outside
* of the TPS65090 sub-device drivers
*/
-extern int tps65090_write(struct device *dev, int reg, uint8_t val);
-extern int tps65090_writes(struct device *dev, int reg, int len, uint8_t *val);
-extern int tps65090_read(struct device *dev, int reg, uint8_t *val);
-extern int tps65090_reads(struct device *dev, int reg, int len, uint8_t *val);
-extern int tps65090_set_bits(struct device *dev, int reg, uint8_t bit_num);
-extern int tps65090_clr_bits(struct device *dev, int reg, uint8_t bit_num);
-extern int tps65090_update(struct device *dev, int reg, uint8_t val,
- uint8_t bit_num);
+static inline int tps65090_write(struct device *dev, int reg, uint8_t val)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+
+ return regmap_write(tps->rmap, reg, val);
+}
+
+static inline int tps65090_read(struct device *dev, int reg, uint8_t *val)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+ unsigned int temp_val;
+ int ret;
+
+ ret = regmap_read(tps->rmap, reg, &temp_val);
+ if (!ret)
+ *val = temp_val;
+ return ret;
+}
+
+static inline int tps65090_set_bits(struct device *dev, int reg,
+ uint8_t bit_num)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+
+ return regmap_update_bits(tps->rmap, reg, BIT(bit_num), ~0u);
+}
+
+static inline int tps65090_clr_bits(struct device *dev, int reg,
+ uint8_t bit_num)
+{
+ struct tps65090 *tps = dev_get_drvdata(dev);
+
+ return regmap_update_bits(tps->rmap, reg, BIT(bit_num), 0u);
+}
#endif /*__LINUX_MFD_TPS65090_H */
diff --git a/include/linux/mfd/tps80031.h b/include/linux/mfd/tps80031.h
index b3b9480ce596..2fa29e910ba2 100644
--- a/include/linux/mfd/tps80031.h
+++ b/include/linux/mfd/tps80031.h
@@ -184,9 +184,12 @@ struct tps80031_pupd_init_data {
int setting;
};
+struct tps80031_bg_platform_data {
+ int irq_base;
+ int battery_present;
+};
+
struct tps80031_platform_data {
- int num_subdevs;
- struct tps80031_subdev_info *subdevs;
int gpio_base;
int irq_base;
struct tps80031_32kclock_plat_data *clk32k_pdata;
@@ -197,12 +200,13 @@ struct tps80031_platform_data {
bool use_power_off;
struct tps80031_pupd_init_data *pupd_init_data;
int pupd_init_data_size;
+ struct tps80031_regulator_platform_data **regulator_pdata;
+ int num_regulator_pdata;
+ struct tps80031_rtc_platform_data *rtc_pdata;
+ struct tps80031_bg_platform_data *bg_pdata;
+ struct tps80031_charger_platform_data *battery_charger_pdata;
};
-struct tps80031_bg_platform_data {
- int irq_base;
- int battery_present;
-};
/*
* NOTE: the functions below are not intended for use outside
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8f17619931ab..4d50754f339e 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -188,7 +188,11 @@ struct mmc_card {
#define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */
#define MMC_STATE_DOING_BKOPS (1<<6) /* Card doing bkops */
#define MMC_STATE_NEED_BKOPS (1<<7) /* Card needs to do bkops */
-#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
+#define MMC_CARD_SDXC (1<<8) /* card is SDXC */
+#define MMC_CARD_REMOVED (1<<9) /* card has been removed */
+#define MMC_STATE_HIGHSPEED_200 (1<<10) /* card is in HS200 mode */
+#define MMC_STATE_SLEEP (1<<11) /* card is in sleep state */
+
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -332,6 +336,9 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
#define mmc_card_need_bkops(c) ((c)->state & MMC_STATE_NEED_BKOPS)
+#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
+#define mmc_card_is_sleep(c) ((c)->state & MMC_STATE_SLEEP)
+
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
@@ -339,7 +346,10 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
+#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
+#define mmc_card_set_sleep(c) ((c)->state |= MMC_STATE_SLEEP)
+#define mmc_card_clr_sleep(c) ((c)->state &= ~MMC_STATE_SLEEP)
/*
* Quirk add/remove for MMC products.
*/
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 8c0bf3f2a36f..0441661ad59a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -232,6 +232,13 @@ struct mmc_host {
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_BKOPS (1 << 31) /* Host supports BKOPS */
+ unsigned int caps2; /* More host capabilities */
+#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
+#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
+#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */
+#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
+#define MMC_CAP2_NO_SLEEP_CMD (1 << 4) /* Don't allow sleep command */
+
mmc_pm_flag_t pm_caps; /* supported pm features */
#ifdef CONFIG_MMC_CLKGATE
@@ -401,6 +408,9 @@ int mmc_host_enable(struct mmc_host *host);
int mmc_host_disable(struct mmc_host *host);
int mmc_host_lazy_disable(struct mmc_host *host);
int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
+int mmc_speed_class_control(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg);
+
static inline void mmc_set_disable_delay(struct mmc_host *host,
unsigned int disable_delay)
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
index 1ebcf9ba1256..e65bf7c9dab0 100644
--- a/include/linux/mmc/sd.h
+++ b/include/linux/mmc/sd.h
@@ -19,6 +19,10 @@
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
+ /* class 2 */
+#define SD_SEND_TUNING_PATTERN 19 /* adtc R1 */
+#define SD_SPEED_CLASS_CONTROL 20 /* ac R1b */
+
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
@@ -91,4 +95,13 @@
#define SD_SWITCH_ACCESS_DEF 0
#define SD_SWITCH_ACCESS_HS 1
+/*
+ * SD_SPEED_CLASS_CONTROL definitions
+ */
+#define SD_SPEED_CLASS_CONTROL_START_REC 0x0
+#define SD_SPEED_CLASS_CONTROL_CREATE_DIR 0x1
+#define SD_SPEED_CLASS_CONTROL_UPDATE_CI 0x4
+
+
#endif /* LINUX_MMC_SD_H */
+
diff --git a/include/linux/nvhost.h b/include/linux/nvhost.h
index cde63fa6abb7..d7d8ad04653d 100644
--- a/include/linux/nvhost.h
+++ b/include/linux/nvhost.h
@@ -172,6 +172,10 @@ struct nvhost_driver {
/* Allocates a context handler for the device */
struct nvhost_hwctx_handler *(*alloc_hwctx_handler)(u32 syncpt,
u32 waitbase, struct nvhost_channel *ch);
+
+ /* Clock gating callbacks */
+ int (*prepare_clockoff)(struct nvhost_device *dev);
+ void (*finalize_clockon)(struct nvhost_device *dev);
};
extern int nvhost_driver_register(struct nvhost_driver *);
@@ -209,4 +213,6 @@ 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);
+void nvhost_scale3d_set_throughput_hint(int hint);
+
#endif
diff --git a/include/linux/nvmap.h b/include/linux/nvmap.h
index 553a7bd01a6d..692956b2fc4f 100644
--- a/include/linux/nvmap.h
+++ b/include/linux/nvmap.h
@@ -3,7 +3,7 @@
*
* structure declarations for nvmem and nvmap user-space ioctls
*
- * 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
@@ -49,6 +49,7 @@
#define NVMAP_HANDLE_CACHE_FLAG (0x3ul << 0)
#define NVMAP_HANDLE_SECURE (0x1ul << 2)
+#define NVMAP_HANDLE_ZEROED_PAGES (0x1ul << 3)
#if defined(__KERNEL__)
diff --git a/include/linux/platform_data/tegra_nor.h b/include/linux/platform_data/tegra_nor.h
index cd8faff2f1cd..4bd980d2195b 100644
--- a/include/linux/platform_data/tegra_nor.h
+++ b/include/linux/platform_data/tegra_nor.h
@@ -1,10 +1,5 @@
/*
- * include/linux/platform_data/tegra_nor.h
- *
- * Copyright (C) 2010 - 2011 NVIDIA Corporation.
- *
- * Author:
- * Raghavendra V K <rvk@nvidia.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
@@ -15,6 +10,11 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
+ * include/linux/platform_data/tegra_nor.h
+ *
+ * Author:
+ * Raghavendra V K <rvk@nvidia.com>
+ *
*/
#ifndef __MACH_TEGRA_NOR_PDATA_H
@@ -22,11 +22,45 @@
#include <asm/mach/flash.h>
+typedef enum {
+ NorMuxMode_ADNonMux,
+ NorMuxMode_ADMux,
+}NorMuxMode;
+
+typedef enum {
+ NorPageLength_Unsupported,
+ NorPageLength_4Word,
+ NorPageLength_8Word,
+}NorPageLength;
+
+typedef enum {
+ NorBurstLength_CntBurst,
+ NorBurstLength_8Word,
+ NorBurstLength_16Word,
+ NorBurstLength_32Word,
+}NorBurstLength;
+
+typedef enum {
+ NorReadMode_Async,
+ NorReadMode_Page,
+ NorReadMode_Burst,
+}NorReadMode;
+
+typedef enum {
+ NorReadyActive_WithData,
+ NorReadyActive_BeforeData,
+}NorReadyActive;
+
struct tegra_nor_chip_parms {
struct {
uint32_t timing0;
uint32_t timing1;
} timing_default, timing_read;
+ NorMuxMode MuxMode;
+ NorReadMode ReadMode;
+ NorPageLength PageLength;
+ NorBurstLength BurstLength;
+ NorReadyActive ReadyActive;
};
struct tegra_nor_platform_data {
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
index 6499eeaff6a3..9ad666f987ea 100644
--- a/include/linux/platform_data/tegra_usb.h
+++ b/include/linux/platform_data/tegra_usb.h
@@ -65,17 +65,6 @@ struct tegra_ulpi_config {
};
/**
- * 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.
*/
@@ -134,7 +123,6 @@ struct tegra_usb_platform_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;
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 1a80bc77517d..65ca5ff023ea 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -153,6 +153,7 @@ enum regulator_type {
* this type.
*
* @name: Identifying name for the regulator.
+ * @supply_name: Identifying the regulator supply
* @id: Numerical identifier for the regulator.
* @n_voltages: Number of selectors available for ops.list_voltage().
* @ops: Regulator operations table.
@@ -162,6 +163,7 @@ enum regulator_type {
*/
struct regulator_desc {
const char *name;
+ const char *supply_name;
int id;
unsigned n_voltages;
struct regulator_ops *ops;
diff --git a/include/linux/regulator/tps51632-regulator.h b/include/linux/regulator/tps51632-regulator.h
new file mode 100644
index 000000000000..6dd0b9239698
--- /dev/null
+++ b/include/linux/regulator/tps51632-regulator.h
@@ -0,0 +1,54 @@
+/*
+ * tps51632-regulator.h -- TPS51632 regulator
+ *
+ * Interface for regulator driver for TPS51632 3-2-1 Phase D-Cap Step Down
+ * Driverless Controller with serial VID control and DVFS.
+ *
+ * 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_TPS51632_H
+#define __LINUX_REGULATOR_TPS51632_H
+
+/*
+ * struct tps51632_regulator_platform_data - tps51632 regulator platform data.
+ *
+ * @reg_init_data: The regulator init data.
+ * @enable_pwm: Enable PWM DVFS or not.
+ * @dvfs_step_20mV: Step for DVFS is 20mV or 10mV.
+ * @enable_vmax_alarm: Enable maximum voltage alarm or not.
+ * @enable_overcurrent_alram: Enable overcurrent alarm or not.
+ * @max_voltage_uV: Maximum possible voltage for alarm.
+ * @base_voltage_uV: Base voltage when PWM enabled.
+ * slew_rate_uv_per_us: Slew rate uV/us. The values can be
+ * 6000 to 48000uV/us.
+ */
+struct tps51632_regulator_platform_data {
+ struct regulator_init_data *reg_init_data;
+ bool enable_pwm;
+ bool dvfs_step_20mV;
+ bool enable_vmax_alarm;
+ bool enable_overcurrent_alram;
+ int max_voltage_uV;
+ int base_voltage_uV;
+ unsigned int slew_rate_uv_per_us;
+};
+
+#endif /* __LINUX_REGULATOR_TPS51632_H */
diff --git a/include/linux/regulator/tps65090-regulator.h b/include/linux/regulator/tps65090-regulator.h
index 341d53ec994a..785ca84efa8b 100644
--- a/include/linux/regulator/tps65090-regulator.h
+++ b/include/linux/regulator/tps65090-regulator.h
@@ -1,24 +1,19 @@
/*
- * include/linux/regulator/tps65090-regulator.h
+ * Regulator driver interface for TI TPS65090 PMIC family
*
- * Interface for regulator driver for TI TPS65090 PMIC family
- *
- * 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
+ * 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 Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __REGULATOR_TPS65090_H
@@ -29,32 +24,36 @@
#define tps65090_rails(_name) "tps65090_"#_name
enum {
- TPS65090_ID_DCDC1,
- TPS65090_ID_DCDC2,
- TPS65090_ID_DCDC3,
- TPS65090_ID_FET1,
- TPS65090_ID_FET2,
- TPS65090_ID_FET3,
- TPS65090_ID_FET4,
- TPS65090_ID_FET5,
- TPS65090_ID_FET6,
- TPS65090_ID_FET7,
+ TPS65090_REGULATOR_DCDC1,
+ TPS65090_REGULATOR_DCDC2,
+ TPS65090_REGULATOR_DCDC3,
+ TPS65090_REGULATOR_LDO1,
+ TPS65090_REGULATOR_LDO2,
+ TPS65090_REGULATOR_FET1,
+ TPS65090_REGULATOR_FET2,
+ TPS65090_REGULATOR_FET3,
+ TPS65090_REGULATOR_FET4,
+ TPS65090_REGULATOR_FET5,
+ TPS65090_REGULATOR_FET6,
+ TPS65090_REGULATOR_FET7,
};
/*
* struct tps65090_regulator_platform_data
*
- * @regulator: The regulator init data.
- * @init_uV: initial micro volts which need to be set.
- * @init_enable: Enable or do not enable the rails during initialization.
- * @init_apply: Init parameter applied or not.
- * @slew_rate_uV_per_us: Slew rate microvolt per microsec.
+ * @reg_init_data: The regulator init data.
+ * @id: Regulator ID.
+ * @enable_ext_control: Enable extrenal control or not. Only available for
+ * DCDC1, DCDC2 and DCDC3.
+ * @gpio: Gpio number if external control is enabled and controlled through
+ * gpio.
*/
struct tps65090_regulator_platform_data {
- struct regulator_init_data regulator;
- int slew_rate_uV_per_us;
- unsigned int flags;
+ int id;
+ bool enable_ext_control;
+ int gpio;
+ struct regulator_init_data *reg_init_data;
};
#endif /* __REGULATOR_TPS65090_H */
diff --git a/include/linux/regulator/tps80031-regulator.h b/include/linux/regulator/tps80031-regulator.h
index 4dfdf7950918..f51fd24feff8 100644
--- a/include/linux/regulator/tps80031-regulator.h
+++ b/include/linux/regulator/tps80031-regulator.h
@@ -29,23 +29,26 @@
#define tps80031_rails(_name) "tps80031_"#_name
enum {
- TPS80031_ID_VIO,
- TPS80031_ID_SMPS1,
- TPS80031_ID_SMPS2,
- TPS80031_ID_SMPS3,
- TPS80031_ID_SMPS4,
- TPS80031_ID_VANA,
- TPS80031_ID_LDO1,
- TPS80031_ID_LDO2,
- TPS80031_ID_LDO3,
- TPS80031_ID_LDO4,
- TPS80031_ID_LDO5,
- TPS80031_ID_LDO6,
- TPS80031_ID_LDO7,
- TPS80031_ID_LDOLN,
- TPS80031_ID_LDOUSB,
- TPS80031_ID_VBUS,
- TPS80031_ID_CHARGER,
+ TPS80031_REGULATOR_VIO,
+ TPS80031_REGULATOR_SMPS1,
+ TPS80031_REGULATOR_SMPS2,
+ TPS80031_REGULATOR_SMPS3,
+ TPS80031_REGULATOR_SMPS4,
+ TPS80031_REGULATOR_VANA,
+ TPS80031_REGULATOR_LDO1,
+ TPS80031_REGULATOR_LDO2,
+ TPS80031_REGULATOR_LDO3,
+ TPS80031_REGULATOR_LDO4,
+ TPS80031_REGULATOR_LDO5,
+ TPS80031_REGULATOR_LDO6,
+ TPS80031_REGULATOR_LDO7,
+ TPS80031_REGULATOR_LDOLN,
+ TPS80031_REGULATOR_LDOUSB,
+ TPS80031_REGULATOR_VBUS,
+ TPS80031_REGULATOR_REGEN1,
+ TPS80031_REGULATOR_REGEN2,
+ TPS80031_REGULATOR_SYSEN,
+ TPS80031_REGULATOR_CHARGER,
};
@@ -66,7 +69,8 @@ enum {
/*
* struct tps80031_regulator_platform_data - tps80031 regulator platform data.
*
- * @regulator: The regulator init data.
+ * @regulator_id" Regulator ID.
+ * @reg_init_data: The regulator init data.
* @init_uV: initial micro volts which need to be set.
* @init_enable: Enable or do not enable the rails during initialization.
* @init_apply: Init parameter applied or not.
@@ -80,7 +84,8 @@ enum {
*/
struct tps80031_regulator_platform_data {
- struct regulator_init_data regulator;
+ int regulator_id;
+ struct regulator_init_data *reg_init_data;
int init_uV;
unsigned init_enable:1;
unsigned init_apply:1;
diff --git a/include/linux/tegra_nvavp.h b/include/linux/tegra_nvavp.h
index 6774d0eaa7ef..250eee379de9 100644
--- a/include/linux/tegra_nvavp.h
+++ b/include/linux/tegra_nvavp.h
@@ -1,7 +1,7 @@
/*
* include/linux/tegra_nvavp.h
*
- * Copyright (C) 2011 NVIDIA Corp.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* 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
@@ -89,8 +89,12 @@ struct nvavp_clock_stay_on_state_args {
__u32)
#define NVAVP_IOCTL_FORCE_CLOCK_STAY_ON _IOW(NVAVP_IOCTL_MAGIC, 0x67, \
struct nvavp_clock_stay_on_state_args)
+#define NVAVP_IOCTL_ENABLE_AUDIO_CLOCKS _IOWR(NVAVP_IOCTL_MAGIC, 0x68, \
+ struct nvavp_clock_args)
+#define NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS _IOWR(NVAVP_IOCTL_MAGIC, 0x69, \
+ struct nvavp_clock_args)
#define NVAVP_IOCTL_MIN_NR _IOC_NR(NVAVP_IOCTL_SET_NVMAP_FD)
-#define NVAVP_IOCTL_MAX_NR _IOC_NR(NVAVP_IOCTL_FORCE_CLOCK_STAY_ON)
+#define NVAVP_IOCTL_MAX_NR _IOC_NR(NVAVP_IOCTL_DISABLE_AUDIO_CLOCKS)
#endif /* __LINUX_TEGRA_NVAVP_H */
diff --git a/include/linux/tegra_uart.h b/include/linux/tegra_uart.h
index 38912ea97068..f51b373f8025 100644
--- a/include/linux/tegra_uart.h
+++ b/include/linux/tegra_uart.h
@@ -1,6 +1,6 @@
/* include/linux/tegra_uart.h
*
- * 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
@@ -33,6 +33,12 @@ struct tegra_uart_platform_data {
struct uart_clk_parent *parent_clk_list;
int parent_clk_count;
bool is_loopback;
+ bool is_irda;
+ int (*irda_init)(void);
+ int (*irda_mode_switch)(int);
+ void (*irda_start)(void);
+ void (*irda_shutdown)(void);
+ void (*irda_remove)(void);
};
int tegra_uart_is_tx_empty(struct uart_port *);
diff --git a/include/linux/throughput_ioctl.h b/include/linux/throughput_ioctl.h
new file mode 100644
index 000000000000..96e57399b2e9
--- /dev/null
+++ b/include/linux/throughput_ioctl.h
@@ -0,0 +1,39 @@
+/*
+ * include/linux/throughput_ioctl.h
+ *
+ * ioctl declarations for throughput miscdev
+ *
+ * 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, 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 __TEGRA_THROUGHPUT_IOCTL_H
+#define __TEGRA_THROUGHPUT_IOCTL_H
+
+#include <linux/ioctl.h>
+
+#define TEGRA_THROUGHPUT_MAGIC 'g'
+
+struct tegra_throughput_target_fps_args {
+ __u32 target_fps;
+};
+
+#define TEGRA_THROUGHPUT_IOCTL_TARGET_FPS \
+ _IOW(TEGRA_THROUGHPUT_MAGIC, 1, struct tegra_throughput_target_fps_args)
+#define TEGRA_THROUGHPUT_IOCTL_MAXNR \
+ (_IOC_NR(TEGRA_THROUGHPUT_IOCTL_TARGET_FPS))
+
+#endif /* !defined(__TEGRA_THROUGHPUT_IOCTL_H) */
+
diff --git a/include/linux/usb/f_accessory.h b/include/linux/usb/f_accessory.h
index 5b2dcf9728e1..61ebe0aabc5b 100644
--- a/include/linux/usb/f_accessory.h
+++ b/include/linux/usb/f_accessory.h
@@ -36,13 +36,15 @@
#define ACCESSORY_STRING_URI 4
#define ACCESSORY_STRING_SERIAL 5
-/* Control request for retrieving device's protocol version (currently 1)
+/* Control request for retrieving device's protocol version
*
* requestType: USB_DIR_IN | USB_TYPE_VENDOR
* request: ACCESSORY_GET_PROTOCOL
* value: 0
* index: 0
* data version number (16 bits little endian)
+ * 1 for original accessory support
+ * 2 adds HID and device to host audio support
*/
#define ACCESSORY_GET_PROTOCOL 51
@@ -70,6 +72,65 @@
*/
#define ACCESSORY_START 53
+/* Control request for registering a HID device.
+ * Upon registering, a unique ID is sent by the accessory in the
+ * value parameter. This ID will be used for future commands for
+ * the device
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID_DEVICE
+ * value: Accessory assigned ID for the HID device
+ * index: total length of the HID report descriptor
+ * data none
+ */
+#define ACCESSORY_REGISTER_HID 54
+
+/* Control request for unregistering a HID device.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_REGISTER_HID
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_UNREGISTER_HID 55
+
+/* Control request for sending the HID report descriptor.
+ * If the HID descriptor is longer than the endpoint zero max packet size,
+ * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
+ * commands. The data for the descriptor must be sent sequentially
+ * if multiple packets are needed.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_HID_REPORT_DESC
+ * value: Accessory assigned ID for the HID device
+ * index: offset of data in descriptor
+ * (needed when HID descriptor is too big for one packet)
+ * data the HID report descriptor
+ */
+#define ACCESSORY_SET_HID_REPORT_DESC 56
+
+/* Control request for sending HID events.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SEND_HID_EVENT
+ * value: Accessory assigned ID for the HID device
+ * index: 0
+ * data the HID report for the event
+ */
+#define ACCESSORY_SEND_HID_EVENT 57
+
+/* Control request for setting the audio mode.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SET_AUDIO_MODE
+ * value: 0 - no audio
+ * 1 - device to host, 44100 16-bit stereo PCM
+ * index: 0
+ * data none
+ */
+#define ACCESSORY_SET_AUDIO_MODE 58
+
/* ioctls for retrieving strings set by the host */
#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
@@ -79,5 +140,7 @@
#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
/* returns 1 if there is a start request pending */
#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
+/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
+#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
#endif /* __LINUX_USB_F_ACCESSORY_H */
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index 6939637e787d..b262fd7caa6e 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -192,7 +192,8 @@ extern void usbnet_cdc_status(struct usbnet *, struct urb *);
enum skb_state {
illegal = 0,
tx_start, tx_done,
- rx_start, rx_done, rx_cleanup
+ rx_start, rx_done, rx_cleanup,
+ unlink_start
};
struct skb_data { /* skb->cb is one of these */
diff --git a/include/media/nvc_focus.h b/include/media/nvc_focus.h
index e37d897d8323..2c60db318da2 100644
--- a/include/media/nvc_focus.h
+++ b/include/media/nvc_focus.h
@@ -35,6 +35,14 @@
#define AF_POS_INVALID_VALUE INT_MAX
+/* These are the slew rate values coming down from the configuration */
+/* Disabled is the same as fastest. Default is the default */
+/* slew rate configuration in the focuser */
+#define SLEW_RATE_DISABLED 0
+#define SLEW_RATE_DEFAULT 1
+#define SLEW_RATE_SLOWEST 9
+
+
enum nvc_focus_sts {
NVC_FOCUS_STS_UNKNOWN = 1,
NVC_FOCUS_STS_NO_DEVICE,
diff --git a/include/media/ov9726.h b/include/media/ov9726.h
index b1e759ba583c..fb9995b4a8de 100644
--- a/include/media/ov9726.h
+++ b/include/media/ov9726.h
@@ -19,7 +19,8 @@
#define OV9726_IOCTL_SET_FRAME_LENGTH _IOW('o', 2, __u32)
#define OV9726_IOCTL_SET_COARSE_TIME _IOW('o', 3, __u32)
#define OV9726_IOCTL_SET_GAIN _IOW('o', 4, __u16)
-#define OV9726_IOCTL_GET_STATUS _IOR('o', 5, __u8)
+#define OV9726_IOCTL_GET_STATUS _IOR('o', 5, __u8)
+#define OV9726_IOCTL_SET_GROUP_HOLD _IOW('o', 6, struct ov9726_ae)
struct ov9726_mode {
int mode_id;
@@ -30,6 +31,15 @@ struct ov9726_mode {
__u16 gain;
};
+struct ov9726_ae {
+ __u32 frame_length;
+ __u32 coarse_time;
+ __u16 gain;
+ __u8 frame_length_enable;
+ __u8 coarse_time_enable;
+ __u8 gain_enable;
+};
+
struct ov9726_reg {
__u16 addr;
__u16 val;
diff --git a/include/media/tegra_camera.h b/include/media/tegra_camera.h
index 9dea1485781d..3c41864cc71f 100644
--- a/include/media/tegra_camera.h
+++ b/include/media/tegra_camera.h
@@ -2,6 +2,7 @@
* include/linux/tegra_camera.h
*
* 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
@@ -48,6 +49,15 @@ enum StereoCameraMode {
StereoCameraMode_Force32 = 0x7FFFFFFF
};
+struct tegra_camera_platform_data {
+ bool limit_3d_emc_clk;
+};
+
+#if defined(CONFIG_TEGRA_CAMERA)
+int is_tegra_camera_on(void);
+#else
+int is_tegra_camera_on(void) { return 0; }
+#endif
#define TEGRA_CAMERA_IOCTL_ENABLE _IOWR('i', 1, uint)
#define TEGRA_CAMERA_IOCTL_DISABLE _IOWR('i', 2, uint)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index e0583b7769cb..3bfd6e58b60c 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -408,6 +408,11 @@ enum snd_soc_dapm_type {
snd_soc_dapm_aif_out, /* audio interface output */
};
+enum snd_soc_dapm_subclass {
+ SND_SOC_DAPM_CLASS_INIT = 0,
+ SND_SOC_DAPM_CLASS_PCM = 1,
+};
+
/*
* DAPM audio route definition.
*
diff --git a/include/sound/soc.h b/include/sound/soc.h
index aa19f5a32ba8..878807c0c283 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -751,6 +751,7 @@ struct snd_soc_card {
struct list_head list;
struct mutex mutex;
+ struct mutex dapm_mutex;
bool instantiated;
diff --git a/include/trace/events/nvevent.h b/include/trace/events/nvevent.h
new file mode 100644
index 000000000000..30987129deaf
--- /dev/null
+++ b/include/trace/events/nvevent.h
@@ -0,0 +1,100 @@
+/*
+ * include/trace/events/nvevent.h
+ *
+ * Input 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 nvevent
+
+#if !defined(_TRACE_NVEVENT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NVEVENT_H
+
+#include <linux/ktime.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(nvevent_irq_data_read_start_series,
+ TP_PROTO(const char *name),
+ TP_ARGS(name),
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ ),
+ TP_fast_assign(
+ __entry->name = name;
+ ),
+ TP_printk("name=%s",
+ __entry->name)
+);
+
+TRACE_EVENT(nvevent_irq_data_read_finish_series,
+ TP_PROTO(const char *name),
+ TP_ARGS(name),
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ ),
+ TP_fast_assign(
+ __entry->name = name;
+ ),
+ TP_printk("name=%s",
+ __entry->name)
+);
+
+TRACE_EVENT(nvevent_irq_data_read_start_single,
+ TP_PROTO(const char *name),
+ TP_ARGS(name),
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ ),
+ TP_fast_assign(
+ __entry->name = name;
+ ),
+ TP_printk("name=%s",
+ __entry->name)
+);
+
+TRACE_EVENT(nvevent_irq_data_read_finish_single,
+ TP_PROTO(const char *name),
+ TP_ARGS(name),
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ ),
+ TP_fast_assign(
+ __entry->name = name;
+ ),
+ TP_printk("name=%s",
+ __entry->name)
+);
+
+TRACE_EVENT(nvevent_irq_data_submit,
+ TP_PROTO(const char *name),
+ TP_ARGS(name),
+ TP_STRUCT__entry(
+ __field(const char *, name)
+ ),
+ TP_fast_assign(
+ __entry->name = name;
+ ),
+ TP_printk("name=%s",
+ __entry->name)
+);
+
+#endif /* _TRACE_NVEVENT_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 5b503e9b661c..a6be189a2b5f 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -306,6 +306,20 @@ DEFINE_EVENT(clock, clock_set_rate,
TP_ARGS(name, state, cpu_id)
);
+DEFINE_EVENT(clock, clock_lock,
+
+ TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+ TP_ARGS(name, state, cpu_id)
+);
+
+DEFINE_EVENT(clock, clock_unlock,
+
+ TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+ TP_ARGS(name, state, cpu_id)
+);
+
/*
* The power domain events are used for power domains transitions
*/
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
index 7d497291c85d..82f61f4ce7a7 100644
--- a/include/trace/events/workqueue.h
+++ b/include/trace/events/workqueue.h
@@ -54,7 +54,7 @@ TRACE_EVENT(workqueue_queue_work,
__entry->function = work->func;
__entry->workqueue = cwq->wq;
__entry->req_cpu = req_cpu;
- __entry->cpu = cwq->gcwq->cpu;
+ __entry->cpu = cwq->pool->gcwq->cpu;
),
TP_printk("work struct=%p function=%pf workqueue=%p req_cpu=%u cpu=%u",
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 4ba7cccb4994..390ef119aa50 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/freezer.h>
+#include <linux/preempt.h>
#include <trace/events/sched.h>
static DEFINE_SPINLOCK(kthread_create_lock);
@@ -88,7 +89,17 @@ static int kthread(void *_create)
/* OK, tell user we're spawned, wait for stop or wakeup */
__set_current_state(TASK_UNINTERRUPTIBLE);
create->result = current;
+
+ /*
+ * Disable preemption so we enter TASK_UNINTERRUPTIBLE after
+ * complete() instead of possibly being preempted. This speeds
+ * up clients that do a kthread_bind() directly after
+ * creation.
+ */
+ preempt_disable();
complete(&create->done);
+ preempt_enable_no_resched();
+
schedule();
ret = -EINTR;
diff --git a/kernel/pm_qos_params.c b/kernel/pm_qos_params.c
index 82da7ac3b1f3..c52405ce4d78 100644
--- a/kernel/pm_qos_params.c
+++ b/kernel/pm_qos_params.c
@@ -174,6 +174,8 @@ static const struct file_operations pm_qos_power_fops = {
.llseek = noop_llseek,
};
+static bool pm_qos_enabled __read_mostly = true;
+
/* unlocked internal variant */
static inline int pm_qos_get_value(struct pm_qos_object *o)
{
@@ -226,8 +228,11 @@ static void update_target(struct pm_qos_object *o, struct plist_node *node,
} else {
plist_add(node, &o->requests);
}
- curr_value = pm_qos_get_value(o);
- pm_qos_set_value(o, curr_value);
+ if (pm_qos_enabled) {
+ curr_value = pm_qos_get_value(o);
+ pm_qos_set_value(o, curr_value);
+ } else
+ curr_value = o->default_value;
spin_unlock_irqrestore(&pm_qos_lock, flags);
if (prev_value != curr_value)
@@ -372,6 +377,58 @@ void pm_qos_remove_request(struct pm_qos_request_list *pm_qos_req)
}
EXPORT_SYMBOL_GPL(pm_qos_remove_request);
+static int pm_qos_enabled_set(const char *arg, const struct kernel_param *kp)
+{
+ unsigned long flags;
+ bool old;
+ s32 prev[PM_QOS_NUM_CLASSES], curr[PM_QOS_NUM_CLASSES];
+ int ret, i;
+
+ old = pm_qos_enabled;
+ ret = param_set_bool(arg, kp);
+ if (ret != 0) {
+ pr_warn("%s: cannot set PM QoS enable to %s\n",
+ __FUNCTION__, arg);
+ return ret;
+ }
+ spin_lock_irqsave(&pm_qos_lock, flags);
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++)
+ prev[i] = pm_qos_read_value(pm_qos_array[i]);
+ if (old && !pm_qos_enabled) {
+ /* got disabled */
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++) {
+ curr[i] = pm_qos_array[i]->default_value;
+ pm_qos_set_value(pm_qos_array[i], curr[i]);
+ }
+ } else if (!old && pm_qos_enabled) {
+ /* got enabled */
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++) {
+ curr[i] = pm_qos_get_value(pm_qos_array[i]);
+ pm_qos_set_value(pm_qos_array[i], curr[i]);
+ }
+ }
+ spin_unlock_irqrestore(&pm_qos_lock, flags);
+ for (i = 1; i < PM_QOS_NUM_CLASSES; i++)
+ if (prev[i] != curr[i])
+ blocking_notifier_call_chain(
+ pm_qos_array[i]->notifiers,
+ (unsigned long)curr[i],
+ NULL);
+
+ return ret;
+}
+
+static int pm_qos_enabled_get(char *buffer, const struct kernel_param *kp)
+{
+ return param_get_bool(buffer, kp);
+}
+
+static struct kernel_param_ops pm_qos_enabled_ops = {
+ .set = pm_qos_enabled_set,
+ .get = pm_qos_enabled_get,
+};
+module_param_cb(enable, &pm_qos_enabled_ops, &pm_qos_enabled, 0644);
+
/**
* pm_qos_add_notifier - sets notification entry for changes to target value
* @pm_qos_class: identifies which qos target changes should be notified.
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 1783aabc6128..cc09c562e479 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -45,32 +45,41 @@
#include "workqueue_sched.h"
enum {
- /* global_cwq flags */
- GCWQ_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
- GCWQ_MANAGING_WORKERS = 1 << 1, /* managing workers */
- GCWQ_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */
- GCWQ_FREEZING = 1 << 3, /* freeze in progress */
- GCWQ_HIGHPRI_PENDING = 1 << 4, /* highpri works on queue */
+ /*
+ * global_cwq flags
+ *
+ * A bound gcwq is either associated or disassociated with its CPU.
+ * While associated (!DISASSOCIATED), all workers are bound to the
+ * CPU and none has %WORKER_UNBOUND set and concurrency management
+ * is in effect.
+ *
+ * While DISASSOCIATED, the cpu may be offline and all workers have
+ * %WORKER_UNBOUND set and concurrency management disabled, and may
+ * be executing on any CPU. The gcwq behaves as an unbound one.
+ *
+ * Note that DISASSOCIATED can be flipped only while holding
+ * managership of all pools on the gcwq to avoid changing binding
+ * state while create_worker() is in progress.
+ */
+ GCWQ_DISASSOCIATED = 1 << 0, /* cpu can't serve workers */
+ GCWQ_FREEZING = 1 << 1, /* freeze in progress */
+
+ /* pool flags */
+ POOL_MANAGE_WORKERS = 1 << 0, /* need to manage workers */
/* worker flags */
WORKER_STARTED = 1 << 0, /* started */
WORKER_DIE = 1 << 1, /* die die die */
WORKER_IDLE = 1 << 2, /* is idle */
WORKER_PREP = 1 << 3, /* preparing to run works */
- WORKER_ROGUE = 1 << 4, /* not bound to any cpu */
WORKER_REBIND = 1 << 5, /* mom is home, come back */
WORKER_CPU_INTENSIVE = 1 << 6, /* cpu intensive */
WORKER_UNBOUND = 1 << 7, /* worker is unbound */
- WORKER_NOT_RUNNING = WORKER_PREP | WORKER_ROGUE | WORKER_REBIND |
- WORKER_CPU_INTENSIVE | WORKER_UNBOUND,
+ WORKER_NOT_RUNNING = WORKER_PREP | WORKER_REBIND | WORKER_UNBOUND |
+ WORKER_CPU_INTENSIVE,
- /* gcwq->trustee_state */
- TRUSTEE_START = 0, /* start */
- TRUSTEE_IN_CHARGE = 1, /* trustee in charge of gcwq */
- TRUSTEE_BUTCHER = 2, /* butcher workers */
- TRUSTEE_RELEASE = 3, /* release workers */
- TRUSTEE_DONE = 4, /* trustee is done */
+ NR_WORKER_POOLS = 2, /* # worker pools per gcwq */
BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */
BUSY_WORKER_HASH_SIZE = 1 << BUSY_WORKER_HASH_ORDER,
@@ -84,13 +93,13 @@ enum {
(min two ticks) */
MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */
CREATE_COOLDOWN = HZ, /* time to breath after fail */
- TRUSTEE_COOLDOWN = HZ / 10, /* for trustee draining */
/*
* Rescue workers are used only on emergencies and shared by
* all cpus. Give -20.
*/
RESCUER_NICE_LEVEL = -20,
+ HIGHPRI_NICE_LEVEL = -20,
};
/*
@@ -115,6 +124,8 @@ enum {
*/
struct global_cwq;
+struct worker_pool;
+struct idle_rebind;
/*
* The poor guys doing the actual heavy lifting. All on-duty workers
@@ -131,12 +142,31 @@ struct worker {
struct cpu_workqueue_struct *current_cwq; /* L: current_work's cwq */
struct list_head scheduled; /* L: scheduled works */
struct task_struct *task; /* I: worker task */
- struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct worker_pool *pool; /* I: the associated pool */
/* 64 bytes boundary on 64bit, 32 on 32bit */
unsigned long last_active; /* L: last active timestamp */
unsigned int flags; /* X: flags */
int id; /* I: worker id */
- struct work_struct rebind_work; /* L: rebind worker to cpu */
+
+ /* for rebinding worker to CPU */
+ struct idle_rebind *idle_rebind; /* L: for idle worker */
+ struct work_struct rebind_work; /* L: for busy worker */
+};
+
+struct worker_pool {
+ struct global_cwq *gcwq; /* I: the owning gcwq */
+ unsigned int flags; /* X: flags */
+
+ struct list_head worklist; /* L: list of pending works */
+ int nr_workers; /* L: total number of workers */
+ int nr_idle; /* L: currently idle ones */
+
+ struct list_head idle_list; /* X: list of idle workers */
+ struct timer_list idle_timer; /* L: worker idle timeout */
+ struct timer_list mayday_timer; /* L: SOS timer for dworkers */
+
+ struct mutex manager_mutex; /* mutex manager should hold */
+ struct ida worker_ida; /* L: for worker IDs */
};
/*
@@ -146,27 +176,16 @@ struct worker {
*/
struct global_cwq {
spinlock_t lock; /* the gcwq lock */
- struct list_head worklist; /* L: list of pending works */
unsigned int cpu; /* I: the associated cpu */
unsigned int flags; /* L: GCWQ_* flags */
- int nr_workers; /* L: total number of workers */
- int nr_idle; /* L: currently idle ones */
-
- /* workers are chained either in the idle_list or busy_hash */
- struct list_head idle_list; /* X: list of idle workers */
+ /* workers are chained either in busy_head or pool idle_list */
struct hlist_head busy_hash[BUSY_WORKER_HASH_SIZE];
/* L: hash of busy workers */
- struct timer_list idle_timer; /* L: worker idle timeout */
- struct timer_list mayday_timer; /* L: SOS timer for dworkers */
-
- struct ida worker_ida; /* L: for worker IDs */
+ struct worker_pool pools[2]; /* normal and highpri pools */
- struct task_struct *trustee; /* L: for gcwq shutdown */
- unsigned int trustee_state; /* L: trustee state */
- wait_queue_head_t trustee_wait; /* trustee wait */
- struct worker *first_idle; /* L: first idle worker */
+ wait_queue_head_t rebind_hold; /* rebind hold wait */
} ____cacheline_aligned_in_smp;
/*
@@ -175,7 +194,7 @@ struct global_cwq {
* aligned at two's power of the number of flag bits.
*/
struct cpu_workqueue_struct {
- struct global_cwq *gcwq; /* I: the associated gcwq */
+ struct worker_pool *pool; /* I: the associated pool */
struct workqueue_struct *wq; /* I: the owning workqueue */
int work_color; /* L: current color */
int flush_color; /* L: flushing color */
@@ -262,6 +281,10 @@ EXPORT_SYMBOL_GPL(system_freezable_wq);
#define CREATE_TRACE_POINTS
#include <trace/events/workqueue.h>
+#define for_each_worker_pool(pool, gcwq) \
+ for ((pool) = &(gcwq)->pools[0]; \
+ (pool) < &(gcwq)->pools[NR_WORKER_POOLS]; (pool)++)
+
#define for_each_busy_worker(worker, i, pos, gcwq) \
for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++) \
hlist_for_each_entry(worker, pos, &gcwq->busy_hash[i], hentry)
@@ -442,7 +465,7 @@ static bool workqueue_freezing; /* W: have wqs started freezing? */
* try_to_wake_up(). Put it in a separate cacheline.
*/
static DEFINE_PER_CPU(struct global_cwq, global_cwq);
-static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, gcwq_nr_running);
+static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, pool_nr_running[NR_WORKER_POOLS]);
/*
* Global cpu workqueue and nr_running counter for unbound gcwq. The
@@ -450,10 +473,17 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(atomic_t, gcwq_nr_running);
* workers have WORKER_UNBOUND set.
*/
static struct global_cwq unbound_global_cwq;
-static atomic_t unbound_gcwq_nr_running = ATOMIC_INIT(0); /* always 0 */
+static atomic_t unbound_pool_nr_running[NR_WORKER_POOLS] = {
+ [0 ... NR_WORKER_POOLS - 1] = ATOMIC_INIT(0), /* always 0 */
+};
static int worker_thread(void *__worker);
+static int worker_pool_pri(struct worker_pool *pool)
+{
+ return pool - pool->gcwq->pools;
+}
+
static struct global_cwq *get_gcwq(unsigned int cpu)
{
if (cpu != WORK_CPU_UNBOUND)
@@ -462,12 +492,17 @@ static struct global_cwq *get_gcwq(unsigned int cpu)
return &unbound_global_cwq;
}
-static atomic_t *get_gcwq_nr_running(unsigned int cpu)
+static atomic_t *get_pool_nr_running(struct worker_pool *pool)
{
+ int cpu = pool->gcwq->cpu;
+ atomic_t (*nr_running)[NR_WORKER_POOLS];
+
if (cpu != WORK_CPU_UNBOUND)
- return &per_cpu(gcwq_nr_running, cpu);
+ nr_running = &per_cpu(pool_nr_running, cpu);
else
- return &unbound_gcwq_nr_running;
+ nr_running = &unbound_pool_nr_running;
+
+ return nr_running[worker_pool_pri(pool)];
}
static struct cpu_workqueue_struct *get_cwq(unsigned int cpu,
@@ -558,7 +593,7 @@ static struct global_cwq *get_work_gcwq(struct work_struct *work)
if (data & WORK_STRUCT_CWQ)
return ((struct cpu_workqueue_struct *)
- (data & WORK_STRUCT_WQ_DATA_MASK))->gcwq;
+ (data & WORK_STRUCT_WQ_DATA_MASK))->pool->gcwq;
cpu = data >> WORK_STRUCT_FLAG_BITS;
if (cpu == WORK_CPU_NONE)
@@ -569,60 +604,62 @@ static struct global_cwq *get_work_gcwq(struct work_struct *work)
}
/*
- * Policy functions. These define the policies on how the global
- * worker pool is managed. Unless noted otherwise, these functions
- * assume that they're being called with gcwq->lock held.
+ * Policy functions. These define the policies on how the global worker
+ * pools are managed. Unless noted otherwise, these functions assume that
+ * they're being called with gcwq->lock held.
*/
-static bool __need_more_worker(struct global_cwq *gcwq)
+static bool __need_more_worker(struct worker_pool *pool)
{
- return !atomic_read(get_gcwq_nr_running(gcwq->cpu)) ||
- gcwq->flags & GCWQ_HIGHPRI_PENDING;
+ return !atomic_read(get_pool_nr_running(pool));
}
/*
* Need to wake up a worker? Called from anything but currently
* running workers.
+ *
+ * Note that, because unbound workers never contribute to nr_running, this
+ * function will always return %true for unbound gcwq as long as the
+ * worklist isn't empty.
*/
-static bool need_more_worker(struct global_cwq *gcwq)
+static bool need_more_worker(struct worker_pool *pool)
{
- return !list_empty(&gcwq->worklist) && __need_more_worker(gcwq);
+ return !list_empty(&pool->worklist) && __need_more_worker(pool);
}
/* Can I start working? Called from busy but !running workers. */
-static bool may_start_working(struct global_cwq *gcwq)
+static bool may_start_working(struct worker_pool *pool)
{
- return gcwq->nr_idle;
+ return pool->nr_idle;
}
/* Do I need to keep working? Called from currently running workers. */
-static bool keep_working(struct global_cwq *gcwq)
+static bool keep_working(struct worker_pool *pool)
{
- atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+ atomic_t *nr_running = get_pool_nr_running(pool);
- return !list_empty(&gcwq->worklist) &&
- (atomic_read(nr_running) <= 1 ||
- gcwq->flags & GCWQ_HIGHPRI_PENDING);
+ return !list_empty(&pool->worklist) && atomic_read(nr_running) <= 1;
}
/* Do we need a new worker? Called from manager. */
-static bool need_to_create_worker(struct global_cwq *gcwq)
+static bool need_to_create_worker(struct worker_pool *pool)
{
- return need_more_worker(gcwq) && !may_start_working(gcwq);
+ return need_more_worker(pool) && !may_start_working(pool);
}
/* Do I need to be the manager? */
-static bool need_to_manage_workers(struct global_cwq *gcwq)
+static bool need_to_manage_workers(struct worker_pool *pool)
{
- return need_to_create_worker(gcwq) || gcwq->flags & GCWQ_MANAGE_WORKERS;
+ return need_to_create_worker(pool) ||
+ (pool->flags & POOL_MANAGE_WORKERS);
}
/* Do we have too many workers and should some go away? */
-static bool too_many_workers(struct global_cwq *gcwq)
+static bool too_many_workers(struct worker_pool *pool)
{
- bool managing = gcwq->flags & GCWQ_MANAGING_WORKERS;
- int nr_idle = gcwq->nr_idle + managing; /* manager is considered idle */
- int nr_busy = gcwq->nr_workers - nr_idle;
+ bool managing = mutex_is_locked(&pool->manager_mutex);
+ int nr_idle = pool->nr_idle + managing; /* manager is considered idle */
+ int nr_busy = pool->nr_workers - nr_idle;
return nr_idle > 2 && (nr_idle - 2) * MAX_IDLE_WORKERS_RATIO >= nr_busy;
}
@@ -632,26 +669,26 @@ static bool too_many_workers(struct global_cwq *gcwq)
*/
/* Return the first worker. Safe with preemption disabled */
-static struct worker *first_worker(struct global_cwq *gcwq)
+static struct worker *first_worker(struct worker_pool *pool)
{
- if (unlikely(list_empty(&gcwq->idle_list)))
+ if (unlikely(list_empty(&pool->idle_list)))
return NULL;
- return list_first_entry(&gcwq->idle_list, struct worker, entry);
+ return list_first_entry(&pool->idle_list, struct worker, entry);
}
/**
* wake_up_worker - wake up an idle worker
- * @gcwq: gcwq to wake worker for
+ * @pool: worker pool to wake worker from
*
- * Wake up the first idle worker of @gcwq.
+ * Wake up the first idle worker of @pool.
*
* CONTEXT:
* spin_lock_irq(gcwq->lock).
*/
-static void wake_up_worker(struct global_cwq *gcwq)
+static void wake_up_worker(struct worker_pool *pool)
{
- struct worker *worker = first_worker(gcwq);
+ struct worker *worker = first_worker(pool);
if (likely(worker))
wake_up_process(worker->task);
@@ -673,7 +710,7 @@ void wq_worker_waking_up(struct task_struct *task, unsigned int cpu)
struct worker *worker = kthread_data(task);
if (!(worker->flags & WORKER_NOT_RUNNING))
- atomic_inc(get_gcwq_nr_running(cpu));
+ atomic_inc(get_pool_nr_running(worker->pool));
}
/**
@@ -695,8 +732,8 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task,
unsigned int cpu)
{
struct worker *worker = kthread_data(task), *to_wakeup = NULL;
- struct global_cwq *gcwq = get_gcwq(cpu);
- atomic_t *nr_running = get_gcwq_nr_running(cpu);
+ struct worker_pool *pool = worker->pool;
+ atomic_t *nr_running = get_pool_nr_running(pool);
if (worker->flags & WORKER_NOT_RUNNING)
return NULL;
@@ -709,14 +746,14 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task,
* worklist not empty test sequence is in insert_work().
* Please read comment there.
*
- * NOT_RUNNING is clear. This means that trustee is not in
- * charge and we're running on the local cpu w/ rq lock held
- * and preemption disabled, which in turn means that none else
- * could be manipulating idle_list, so dereferencing idle_list
- * without gcwq lock is safe.
+ * NOT_RUNNING is clear. This means that we're bound to and
+ * running on the local cpu w/ rq lock held and preemption
+ * disabled, which in turn means that none else could be
+ * manipulating idle_list, so dereferencing idle_list without gcwq
+ * lock is safe.
*/
- if (atomic_dec_and_test(nr_running) && !list_empty(&gcwq->worklist))
- to_wakeup = first_worker(gcwq);
+ if (atomic_dec_and_test(nr_running) && !list_empty(&pool->worklist))
+ to_wakeup = first_worker(pool);
return to_wakeup ? to_wakeup->task : NULL;
}
@@ -736,7 +773,7 @@ struct task_struct *wq_worker_sleeping(struct task_struct *task,
static inline void worker_set_flags(struct worker *worker, unsigned int flags,
bool wakeup)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
WARN_ON_ONCE(worker->task != current);
@@ -747,12 +784,12 @@ static inline void worker_set_flags(struct worker *worker, unsigned int flags,
*/
if ((flags & WORKER_NOT_RUNNING) &&
!(worker->flags & WORKER_NOT_RUNNING)) {
- atomic_t *nr_running = get_gcwq_nr_running(gcwq->cpu);
+ atomic_t *nr_running = get_pool_nr_running(pool);
if (wakeup) {
if (atomic_dec_and_test(nr_running) &&
- !list_empty(&gcwq->worklist))
- wake_up_worker(gcwq);
+ !list_empty(&pool->worklist))
+ wake_up_worker(pool);
} else
atomic_dec(nr_running);
}
@@ -772,7 +809,7 @@ static inline void worker_set_flags(struct worker *worker, unsigned int flags,
*/
static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
unsigned int oflags = worker->flags;
WARN_ON_ONCE(worker->task != current);
@@ -786,7 +823,7 @@ static inline void worker_clr_flags(struct worker *worker, unsigned int flags)
*/
if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING))
if (!(worker->flags & WORKER_NOT_RUNNING))
- atomic_inc(get_gcwq_nr_running(gcwq->cpu));
+ atomic_inc(get_pool_nr_running(pool));
}
/**
@@ -870,43 +907,6 @@ static struct worker *find_worker_executing_work(struct global_cwq *gcwq,
}
/**
- * gcwq_determine_ins_pos - find insertion position
- * @gcwq: gcwq of interest
- * @cwq: cwq a work is being queued for
- *
- * A work for @cwq is about to be queued on @gcwq, determine insertion
- * position for the work. If @cwq is for HIGHPRI wq, the work is
- * queued at the head of the queue but in FIFO order with respect to
- * other HIGHPRI works; otherwise, at the end of the queue. This
- * function also sets GCWQ_HIGHPRI_PENDING flag to hint @gcwq that
- * there are HIGHPRI works pending.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- *
- * RETURNS:
- * Pointer to inserstion position.
- */
-static inline struct list_head *gcwq_determine_ins_pos(struct global_cwq *gcwq,
- struct cpu_workqueue_struct *cwq)
-{
- struct work_struct *twork;
-
- if (likely(!(cwq->wq->flags & WQ_HIGHPRI)))
- return &gcwq->worklist;
-
- list_for_each_entry(twork, &gcwq->worklist, entry) {
- struct cpu_workqueue_struct *tcwq = get_work_cwq(twork);
-
- if (!(tcwq->wq->flags & WQ_HIGHPRI))
- break;
- }
-
- gcwq->flags |= GCWQ_HIGHPRI_PENDING;
- return &twork->entry;
-}
-
-/**
* insert_work - insert a work into gcwq
* @cwq: cwq @work belongs to
* @work: work to insert
@@ -923,7 +923,7 @@ static void insert_work(struct cpu_workqueue_struct *cwq,
struct work_struct *work, struct list_head *head,
unsigned int extra_flags)
{
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = cwq->pool;
/* we own @work, set data and link */
set_work_cwq(work, cwq, extra_flags);
@@ -943,8 +943,8 @@ static void insert_work(struct cpu_workqueue_struct *cwq,
*/
smp_mb();
- if (__need_more_worker(gcwq))
- wake_up_worker(gcwq);
+ if (__need_more_worker(pool))
+ wake_up_worker(pool);
}
/*
@@ -1043,7 +1043,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
if (likely(cwq->nr_active < cwq->max_active)) {
trace_workqueue_activate_work(work);
cwq->nr_active++;
- worklist = gcwq_determine_ins_pos(gcwq, cwq);
+ worklist = &cwq->pool->worklist;
} else {
work_flags |= WORK_STRUCT_DELAYED;
worklist = &cwq->delayed_works;
@@ -1192,7 +1192,8 @@ EXPORT_SYMBOL_GPL(queue_delayed_work_on);
*/
static void worker_enter_idle(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
BUG_ON(worker->flags & WORKER_IDLE);
BUG_ON(!list_empty(&worker->entry) &&
@@ -1200,22 +1201,24 @@ static void worker_enter_idle(struct worker *worker)
/* can't use worker_set_flags(), also called from start_worker() */
worker->flags |= WORKER_IDLE;
- gcwq->nr_idle++;
+ pool->nr_idle++;
worker->last_active = jiffies;
/* idle_list is LIFO */
- list_add(&worker->entry, &gcwq->idle_list);
+ list_add(&worker->entry, &pool->idle_list);
- if (likely(!(worker->flags & WORKER_ROGUE))) {
- if (too_many_workers(gcwq) && !timer_pending(&gcwq->idle_timer))
- mod_timer(&gcwq->idle_timer,
- jiffies + IDLE_WORKER_TIMEOUT);
- } else
- wake_up_all(&gcwq->trustee_wait);
+ if (too_many_workers(pool) && !timer_pending(&pool->idle_timer))
+ mod_timer(&pool->idle_timer, jiffies + IDLE_WORKER_TIMEOUT);
- /* sanity check nr_running */
- WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
- atomic_read(get_gcwq_nr_running(gcwq->cpu)));
+ /*
+ * Sanity check nr_running. Because gcwq_unbind_fn() releases
+ * gcwq->lock between setting %WORKER_UNBOUND and zapping
+ * nr_running, the warning may trigger spuriously. Check iff
+ * unbind is not in progress.
+ */
+ WARN_ON_ONCE(!(gcwq->flags & GCWQ_DISASSOCIATED) &&
+ pool->nr_workers == pool->nr_idle &&
+ atomic_read(get_pool_nr_running(pool)));
}
/**
@@ -1229,11 +1232,11 @@ static void worker_enter_idle(struct worker *worker)
*/
static void worker_leave_idle(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
BUG_ON(!(worker->flags & WORKER_IDLE));
worker_clr_flags(worker, WORKER_IDLE);
- gcwq->nr_idle--;
+ pool->nr_idle--;
list_del_init(&worker->entry);
}
@@ -1253,11 +1256,11 @@ static void worker_leave_idle(struct worker *worker)
* verbatim as it's best effort and blocking and gcwq may be
* [dis]associated in the meantime.
*
- * This function tries set_cpus_allowed() and locks gcwq and verifies
- * the binding against GCWQ_DISASSOCIATED which is set during
- * CPU_DYING and cleared during CPU_ONLINE, so if the worker enters
- * idle state or fetches works without dropping lock, it can guarantee
- * the scheduling requirement described in the first paragraph.
+ * This function tries set_cpus_allowed() and locks gcwq and verifies the
+ * binding against %GCWQ_DISASSOCIATED which is set during
+ * %CPU_DOWN_PREPARE and cleared during %CPU_ONLINE, so if the worker
+ * enters idle state or fetches works without dropping lock, it can
+ * guarantee the scheduling requirement described in the first paragraph.
*
* CONTEXT:
* Might sleep. Called without any lock but returns with gcwq->lock
@@ -1270,7 +1273,7 @@ static void worker_leave_idle(struct worker *worker)
static bool worker_maybe_bind_and_lock(struct worker *worker)
__acquires(&gcwq->lock)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct global_cwq *gcwq = worker->pool->gcwq;
struct task_struct *task = worker->task;
while (true) {
@@ -1303,16 +1306,40 @@ __acquires(&gcwq->lock)
}
}
+struct idle_rebind {
+ int cnt; /* # workers to be rebound */
+ struct completion done; /* all workers rebound */
+};
+
+/*
+ * Rebind an idle @worker to its CPU. During CPU onlining, this has to
+ * happen synchronously for idle workers. worker_thread() will test
+ * %WORKER_REBIND before leaving idle and call this function.
+ */
+static void idle_worker_rebind(struct worker *worker)
+{
+ struct global_cwq *gcwq = worker->pool->gcwq;
+
+ /* CPU must be online at this point */
+ WARN_ON(!worker_maybe_bind_and_lock(worker));
+ if (!--worker->idle_rebind->cnt)
+ complete(&worker->idle_rebind->done);
+ spin_unlock_irq(&worker->pool->gcwq->lock);
+
+ /* we did our part, wait for rebind_workers() to finish up */
+ wait_event(gcwq->rebind_hold, !(worker->flags & WORKER_REBIND));
+}
+
/*
- * Function for worker->rebind_work used to rebind rogue busy workers
- * to the associated cpu which is coming back online. This is
- * scheduled by cpu up but can race with other cpu hotplug operations
- * and may be executed twice without intervening cpu down.
+ * Function for @worker->rebind.work used to rebind unbound busy workers to
+ * the associated cpu which is coming back online. This is scheduled by
+ * cpu up but can race with other cpu hotplug operations and may be
+ * executed twice without intervening cpu down.
*/
-static void worker_rebind_fn(struct work_struct *work)
+static void busy_worker_rebind_fn(struct work_struct *work)
{
struct worker *worker = container_of(work, struct worker, rebind_work);
- struct global_cwq *gcwq = worker->gcwq;
+ struct global_cwq *gcwq = worker->pool->gcwq;
if (worker_maybe_bind_and_lock(worker))
worker_clr_flags(worker, WORKER_REBIND);
@@ -1320,6 +1347,112 @@ static void worker_rebind_fn(struct work_struct *work)
spin_unlock_irq(&gcwq->lock);
}
+/**
+ * rebind_workers - rebind all workers of a gcwq to the associated CPU
+ * @gcwq: gcwq of interest
+ *
+ * @gcwq->cpu is coming online. Rebind all workers to the CPU. Rebinding
+ * is different for idle and busy ones.
+ *
+ * The idle ones should be rebound synchronously and idle rebinding should
+ * be complete before any worker starts executing work items with
+ * concurrency management enabled; otherwise, scheduler may oops trying to
+ * wake up non-local idle worker from wq_worker_sleeping().
+ *
+ * This is achieved by repeatedly requesting rebinding until all idle
+ * workers are known to have been rebound under @gcwq->lock and holding all
+ * idle workers from becoming busy until idle rebinding is complete.
+ *
+ * Once idle workers are rebound, busy workers can be rebound as they
+ * finish executing their current work items. Queueing the rebind work at
+ * the head of their scheduled lists is enough. Note that nr_running will
+ * be properbly bumped as busy workers rebind.
+ *
+ * On return, all workers are guaranteed to either be bound or have rebind
+ * work item scheduled.
+ */
+static void rebind_workers(struct global_cwq *gcwq)
+ __releases(&gcwq->lock) __acquires(&gcwq->lock)
+{
+ struct idle_rebind idle_rebind;
+ struct worker_pool *pool;
+ struct worker *worker;
+ struct hlist_node *pos;
+ int i;
+
+ lockdep_assert_held(&gcwq->lock);
+
+ for_each_worker_pool(pool, gcwq)
+ lockdep_assert_held(&pool->manager_mutex);
+
+ /*
+ * Rebind idle workers. Interlocked both ways. We wait for
+ * workers to rebind via @idle_rebind.done. Workers will wait for
+ * us to finish up by watching %WORKER_REBIND.
+ */
+ init_completion(&idle_rebind.done);
+retry:
+ idle_rebind.cnt = 1;
+ INIT_COMPLETION(idle_rebind.done);
+
+ /* set REBIND and kick idle ones, we'll wait for these later */
+ for_each_worker_pool(pool, gcwq) {
+ list_for_each_entry(worker, &pool->idle_list, entry) {
+ if (worker->flags & WORKER_REBIND)
+ continue;
+
+ /* morph UNBOUND to REBIND */
+ worker->flags &= ~WORKER_UNBOUND;
+ worker->flags |= WORKER_REBIND;
+
+ idle_rebind.cnt++;
+ worker->idle_rebind = &idle_rebind;
+
+ /* worker_thread() will call idle_worker_rebind() */
+ wake_up_process(worker->task);
+ }
+ }
+
+ if (--idle_rebind.cnt) {
+ spin_unlock_irq(&gcwq->lock);
+ wait_for_completion(&idle_rebind.done);
+ spin_lock_irq(&gcwq->lock);
+ /* busy ones might have become idle while waiting, retry */
+ goto retry;
+ }
+
+ /*
+ * All idle workers are rebound and waiting for %WORKER_REBIND to
+ * be cleared inside idle_worker_rebind(). Clear and release.
+ * Clearing %WORKER_REBIND from this foreign context is safe
+ * because these workers are still guaranteed to be idle.
+ */
+ for_each_worker_pool(pool, gcwq)
+ list_for_each_entry(worker, &pool->idle_list, entry)
+ worker->flags &= ~WORKER_REBIND;
+
+ wake_up_all(&gcwq->rebind_hold);
+
+ /* rebind busy workers */
+ for_each_busy_worker(worker, i, pos, gcwq) {
+ struct work_struct *rebind_work = &worker->rebind_work;
+
+ /* morph UNBOUND to REBIND */
+ worker->flags &= ~WORKER_UNBOUND;
+ worker->flags |= WORKER_REBIND;
+
+ if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(rebind_work)))
+ continue;
+
+ /* wq doesn't matter, use the default one */
+ debug_work_activate(rebind_work);
+ insert_work(get_cwq(gcwq->cpu, system_wq), rebind_work,
+ worker->scheduled.next,
+ work_color_to_flags(WORK_NO_COLOR));
+ }
+}
+
static struct worker *alloc_worker(void)
{
struct worker *worker;
@@ -1328,7 +1461,7 @@ static struct worker *alloc_worker(void)
if (worker) {
INIT_LIST_HEAD(&worker->entry);
INIT_LIST_HEAD(&worker->scheduled);
- INIT_WORK(&worker->rebind_work, worker_rebind_fn);
+ INIT_WORK(&worker->rebind_work, busy_worker_rebind_fn);
/* on creation a worker is in !idle && prep state */
worker->flags = WORKER_PREP;
}
@@ -1337,10 +1470,9 @@ static struct worker *alloc_worker(void)
/**
* create_worker - create a new workqueue worker
- * @gcwq: gcwq the new worker will belong to
- * @bind: whether to set affinity to @cpu or not
+ * @pool: pool the new worker will belong to
*
- * Create a new worker which is bound to @gcwq. The returned worker
+ * Create a new worker which is bound to @pool. The returned worker
* can be started by calling start_worker() or destroyed using
* destroy_worker().
*
@@ -1350,16 +1482,17 @@ static struct worker *alloc_worker(void)
* RETURNS:
* Pointer to the newly created worker.
*/
-static struct worker *create_worker(struct global_cwq *gcwq, bool bind)
+static struct worker *create_worker(struct worker_pool *pool)
{
- bool on_unbound_cpu = gcwq->cpu == WORK_CPU_UNBOUND;
+ struct global_cwq *gcwq = pool->gcwq;
+ const char *pri = worker_pool_pri(pool) ? "H" : "";
struct worker *worker = NULL;
int id = -1;
spin_lock_irq(&gcwq->lock);
- while (ida_get_new(&gcwq->worker_ida, &id)) {
+ while (ida_get_new(&pool->worker_ida, &id)) {
spin_unlock_irq(&gcwq->lock);
- if (!ida_pre_get(&gcwq->worker_ida, GFP_KERNEL))
+ if (!ida_pre_get(&pool->worker_ida, GFP_KERNEL))
goto fail;
spin_lock_irq(&gcwq->lock);
}
@@ -1369,38 +1502,43 @@ static struct worker *create_worker(struct global_cwq *gcwq, bool bind)
if (!worker)
goto fail;
- worker->gcwq = gcwq;
+ worker->pool = pool;
worker->id = id;
- if (!on_unbound_cpu)
+ if (gcwq->cpu != WORK_CPU_UNBOUND)
worker->task = kthread_create_on_node(worker_thread,
- worker,
- cpu_to_node(gcwq->cpu),
- "kworker/%u:%d", gcwq->cpu, id);
+ worker, cpu_to_node(gcwq->cpu),
+ "kworker/%u:%d%s", gcwq->cpu, id, pri);
else
worker->task = kthread_create(worker_thread, worker,
- "kworker/u:%d", id);
+ "kworker/u:%d%s", id, pri);
if (IS_ERR(worker->task))
goto fail;
+ if (worker_pool_pri(pool))
+ set_user_nice(worker->task, HIGHPRI_NICE_LEVEL);
+
/*
- * A rogue worker will become a regular one if CPU comes
- * online later on. Make sure every worker has
- * PF_THREAD_BOUND set.
+ * Determine CPU binding of the new worker depending on
+ * %GCWQ_DISASSOCIATED. The caller is responsible for ensuring the
+ * flag remains stable across this function. See the comments
+ * above the flag definition for details.
+ *
+ * As an unbound worker may later become a regular one if CPU comes
+ * online, make sure every worker has %PF_THREAD_BOUND set.
*/
- if (bind && !on_unbound_cpu)
+ if (!(gcwq->flags & GCWQ_DISASSOCIATED)) {
kthread_bind(worker->task, gcwq->cpu);
- else {
+ } else {
worker->task->flags |= PF_THREAD_BOUND;
- if (on_unbound_cpu)
- worker->flags |= WORKER_UNBOUND;
+ worker->flags |= WORKER_UNBOUND;
}
return worker;
fail:
if (id >= 0) {
spin_lock_irq(&gcwq->lock);
- ida_remove(&gcwq->worker_ida, id);
+ ida_remove(&pool->worker_ida, id);
spin_unlock_irq(&gcwq->lock);
}
kfree(worker);
@@ -1419,7 +1557,7 @@ fail:
static void start_worker(struct worker *worker)
{
worker->flags |= WORKER_STARTED;
- worker->gcwq->nr_workers++;
+ worker->pool->nr_workers++;
worker_enter_idle(worker);
wake_up_process(worker->task);
}
@@ -1435,7 +1573,8 @@ static void start_worker(struct worker *worker)
*/
static void destroy_worker(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
int id = worker->id;
/* sanity check frenzy */
@@ -1443,9 +1582,9 @@ static void destroy_worker(struct worker *worker)
BUG_ON(!list_empty(&worker->scheduled));
if (worker->flags & WORKER_STARTED)
- gcwq->nr_workers--;
+ pool->nr_workers--;
if (worker->flags & WORKER_IDLE)
- gcwq->nr_idle--;
+ pool->nr_idle--;
list_del_init(&worker->entry);
worker->flags |= WORKER_DIE;
@@ -1456,29 +1595,30 @@ static void destroy_worker(struct worker *worker)
kfree(worker);
spin_lock_irq(&gcwq->lock);
- ida_remove(&gcwq->worker_ida, id);
+ ida_remove(&pool->worker_ida, id);
}
-static void idle_worker_timeout(unsigned long __gcwq)
+static void idle_worker_timeout(unsigned long __pool)
{
- struct global_cwq *gcwq = (void *)__gcwq;
+ struct worker_pool *pool = (void *)__pool;
+ struct global_cwq *gcwq = pool->gcwq;
spin_lock_irq(&gcwq->lock);
- if (too_many_workers(gcwq)) {
+ if (too_many_workers(pool)) {
struct worker *worker;
unsigned long expires;
/* idle_list is kept in LIFO order, check the last one */
- worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ worker = list_entry(pool->idle_list.prev, struct worker, entry);
expires = worker->last_active + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires))
- mod_timer(&gcwq->idle_timer, expires);
+ mod_timer(&pool->idle_timer, expires);
else {
/* it's been idle for too long, wake up manager */
- gcwq->flags |= GCWQ_MANAGE_WORKERS;
- wake_up_worker(gcwq);
+ pool->flags |= POOL_MANAGE_WORKERS;
+ wake_up_worker(pool);
}
}
@@ -1495,7 +1635,7 @@ static bool send_mayday(struct work_struct *work)
return false;
/* mayday mayday mayday */
- cpu = cwq->gcwq->cpu;
+ cpu = cwq->pool->gcwq->cpu;
/* WORK_CPU_UNBOUND can't be set in cpumask, use cpu 0 instead */
if (cpu == WORK_CPU_UNBOUND)
cpu = 0;
@@ -1504,37 +1644,38 @@ static bool send_mayday(struct work_struct *work)
return true;
}
-static void gcwq_mayday_timeout(unsigned long __gcwq)
+static void gcwq_mayday_timeout(unsigned long __pool)
{
- struct global_cwq *gcwq = (void *)__gcwq;
+ struct worker_pool *pool = (void *)__pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct work_struct *work;
spin_lock_irq(&gcwq->lock);
- if (need_to_create_worker(gcwq)) {
+ if (need_to_create_worker(pool)) {
/*
* We've been trying to create a new worker but
* haven't been successful. We might be hitting an
* allocation deadlock. Send distress signals to
* rescuers.
*/
- list_for_each_entry(work, &gcwq->worklist, entry)
+ list_for_each_entry(work, &pool->worklist, entry)
send_mayday(work);
}
spin_unlock_irq(&gcwq->lock);
- mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INTERVAL);
+ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INTERVAL);
}
/**
* maybe_create_worker - create a new worker if necessary
- * @gcwq: gcwq to create a new worker for
+ * @pool: pool to create a new worker for
*
- * Create a new worker for @gcwq if necessary. @gcwq is guaranteed to
+ * Create a new worker for @pool if necessary. @pool is guaranteed to
* have at least one idle worker on return from this function. If
* creating a new worker takes longer than MAYDAY_INTERVAL, mayday is
- * sent to all rescuers with works scheduled on @gcwq to resolve
+ * sent to all rescuers with works scheduled on @pool to resolve
* possible allocation deadlock.
*
* On return, need_to_create_worker() is guaranteed to be false and
@@ -1549,52 +1690,54 @@ static void gcwq_mayday_timeout(unsigned long __gcwq)
* false if no action was taken and gcwq->lock stayed locked, true
* otherwise.
*/
-static bool maybe_create_worker(struct global_cwq *gcwq)
+static bool maybe_create_worker(struct worker_pool *pool)
__releases(&gcwq->lock)
__acquires(&gcwq->lock)
{
- if (!need_to_create_worker(gcwq))
+ struct global_cwq *gcwq = pool->gcwq;
+
+ if (!need_to_create_worker(pool))
return false;
restart:
spin_unlock_irq(&gcwq->lock);
/* if we don't make progress in MAYDAY_INITIAL_TIMEOUT, call for help */
- mod_timer(&gcwq->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
+ mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT);
while (true) {
struct worker *worker;
- worker = create_worker(gcwq, true);
+ worker = create_worker(pool);
if (worker) {
- del_timer_sync(&gcwq->mayday_timer);
+ del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&gcwq->lock);
start_worker(worker);
- BUG_ON(need_to_create_worker(gcwq));
+ BUG_ON(need_to_create_worker(pool));
return true;
}
- if (!need_to_create_worker(gcwq))
+ if (!need_to_create_worker(pool))
break;
__set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(CREATE_COOLDOWN);
- if (!need_to_create_worker(gcwq))
+ if (!need_to_create_worker(pool))
break;
}
- del_timer_sync(&gcwq->mayday_timer);
+ del_timer_sync(&pool->mayday_timer);
spin_lock_irq(&gcwq->lock);
- if (need_to_create_worker(gcwq))
+ if (need_to_create_worker(pool))
goto restart;
return true;
}
/**
* maybe_destroy_worker - destroy workers which have been idle for a while
- * @gcwq: gcwq to destroy workers for
+ * @pool: pool to destroy workers for
*
- * Destroy @gcwq workers which have been idle for longer than
+ * Destroy @pool workers which have been idle for longer than
* IDLE_WORKER_TIMEOUT.
*
* LOCKING:
@@ -1605,19 +1748,19 @@ restart:
* false if no action was taken and gcwq->lock stayed locked, true
* otherwise.
*/
-static bool maybe_destroy_workers(struct global_cwq *gcwq)
+static bool maybe_destroy_workers(struct worker_pool *pool)
{
bool ret = false;
- while (too_many_workers(gcwq)) {
+ while (too_many_workers(pool)) {
struct worker *worker;
unsigned long expires;
- worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
+ worker = list_entry(pool->idle_list.prev, struct worker, entry);
expires = worker->last_active + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires)) {
- mod_timer(&gcwq->idle_timer, expires);
+ mod_timer(&pool->idle_timer, expires);
break;
}
@@ -1650,31 +1793,22 @@ static bool maybe_destroy_workers(struct global_cwq *gcwq)
*/
static bool manage_workers(struct worker *worker)
{
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
bool ret = false;
- if (gcwq->flags & GCWQ_MANAGING_WORKERS)
+ if (!mutex_trylock(&pool->manager_mutex))
return ret;
- gcwq->flags &= ~GCWQ_MANAGE_WORKERS;
- gcwq->flags |= GCWQ_MANAGING_WORKERS;
+ pool->flags &= ~POOL_MANAGE_WORKERS;
/*
* Destroy and then create so that may_start_working() is true
* on return.
*/
- ret |= maybe_destroy_workers(gcwq);
- ret |= maybe_create_worker(gcwq);
-
- gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
-
- /*
- * The trustee might be waiting to take over the manager
- * position, tell it we're done.
- */
- if (unlikely(gcwq->trustee))
- wake_up_all(&gcwq->trustee_wait);
+ ret |= maybe_destroy_workers(pool);
+ ret |= maybe_create_worker(pool);
+ mutex_unlock(&pool->manager_mutex);
return ret;
}
@@ -1723,10 +1857,9 @@ static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
{
struct work_struct *work = list_first_entry(&cwq->delayed_works,
struct work_struct, entry);
- struct list_head *pos = gcwq_determine_ins_pos(cwq->gcwq, cwq);
trace_workqueue_activate_work(work);
- move_linked_works(work, pos, NULL);
+ move_linked_works(work, &cwq->pool->worklist, NULL);
__clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
cwq->nr_active++;
}
@@ -1799,7 +1932,8 @@ __releases(&gcwq->lock)
__acquires(&gcwq->lock)
{
struct cpu_workqueue_struct *cwq = get_work_cwq(work);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct hlist_head *bwh = busy_worker_head(gcwq, work);
bool cpu_intensive = cwq->wq->flags & WQ_CPU_INTENSIVE;
work_func_t f = work->func;
@@ -1815,6 +1949,9 @@ __acquires(&gcwq->lock)
*/
struct lockdep_map lockdep_map = work->lockdep_map;
#endif
+ WARN_ON_ONCE(!(worker->flags & (WORKER_UNBOUND | WORKER_REBIND)) &&
+ raw_smp_processor_id() != gcwq->cpu);
+
/*
* A single work shouldn't be executed concurrently by
* multiple workers on a single cpu. Check whether anyone is
@@ -1839,27 +1976,19 @@ __acquires(&gcwq->lock)
list_del_init(&work->entry);
/*
- * If HIGHPRI_PENDING, check the next work, and, if HIGHPRI,
- * wake up another worker; otherwise, clear HIGHPRI_PENDING.
- */
- if (unlikely(gcwq->flags & GCWQ_HIGHPRI_PENDING)) {
- struct work_struct *nwork = list_first_entry(&gcwq->worklist,
- struct work_struct, entry);
-
- if (!list_empty(&gcwq->worklist) &&
- get_work_cwq(nwork)->wq->flags & WQ_HIGHPRI)
- wake_up_worker(gcwq);
- else
- gcwq->flags &= ~GCWQ_HIGHPRI_PENDING;
- }
-
- /*
* CPU intensive works don't participate in concurrency
* management. They're the scheduler's responsibility.
*/
if (unlikely(cpu_intensive))
worker_set_flags(worker, WORKER_CPU_INTENSIVE, true);
+ /*
+ * Unbound gcwq isn't concurrency managed and work items should be
+ * executed ASAP. Wake up another worker if necessary.
+ */
+ if ((worker->flags & WORKER_UNBOUND) && need_more_worker(pool))
+ wake_up_worker(pool);
+
spin_unlock_irq(&gcwq->lock);
work_clear_pending(work);
@@ -1932,28 +2061,38 @@ static void process_scheduled_works(struct worker *worker)
static int worker_thread(void *__worker)
{
struct worker *worker = __worker;
- struct global_cwq *gcwq = worker->gcwq;
+ struct worker_pool *pool = worker->pool;
+ struct global_cwq *gcwq = pool->gcwq;
/* tell the scheduler that this is a workqueue worker */
worker->task->flags |= PF_WQ_WORKER;
woke_up:
spin_lock_irq(&gcwq->lock);
- /* DIE can be set only while we're idle, checking here is enough */
- if (worker->flags & WORKER_DIE) {
+ /*
+ * DIE can be set only while idle and REBIND set while busy has
+ * @worker->rebind_work scheduled. Checking here is enough.
+ */
+ if (unlikely(worker->flags & (WORKER_REBIND | WORKER_DIE))) {
spin_unlock_irq(&gcwq->lock);
- worker->task->flags &= ~PF_WQ_WORKER;
- return 0;
+
+ if (worker->flags & WORKER_DIE) {
+ worker->task->flags &= ~PF_WQ_WORKER;
+ return 0;
+ }
+
+ idle_worker_rebind(worker);
+ goto woke_up;
}
worker_leave_idle(worker);
recheck:
/* no more worker necessary? */
- if (!need_more_worker(gcwq))
+ if (!need_more_worker(pool))
goto sleep;
/* do we need to manage? */
- if (unlikely(!may_start_working(gcwq)) && manage_workers(worker))
+ if (unlikely(!may_start_working(pool)) && manage_workers(worker))
goto recheck;
/*
@@ -1972,7 +2111,7 @@ recheck:
do {
struct work_struct *work =
- list_first_entry(&gcwq->worklist,
+ list_first_entry(&pool->worklist,
struct work_struct, entry);
if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
@@ -1984,11 +2123,11 @@ recheck:
move_linked_works(work, &worker->scheduled, NULL);
process_scheduled_works(worker);
}
- } while (keep_working(gcwq));
+ } while (keep_working(pool));
worker_set_flags(worker, WORKER_PREP, false);
sleep:
- if (unlikely(need_to_manage_workers(gcwq)) && manage_workers(worker))
+ if (unlikely(need_to_manage_workers(pool)) && manage_workers(worker))
goto recheck;
/*
@@ -2046,14 +2185,15 @@ repeat:
for_each_mayday_cpu(cpu, wq->mayday_mask) {
unsigned int tcpu = is_unbound ? WORK_CPU_UNBOUND : cpu;
struct cpu_workqueue_struct *cwq = get_cwq(tcpu, wq);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct worker_pool *pool = cwq->pool;
+ struct global_cwq *gcwq = pool->gcwq;
struct work_struct *work, *n;
__set_current_state(TASK_RUNNING);
mayday_clear_cpu(cpu, wq->mayday_mask);
/* migrate to the target cpu if possible */
- rescuer->gcwq = gcwq;
+ rescuer->pool = pool;
worker_maybe_bind_and_lock(rescuer);
/*
@@ -2061,7 +2201,7 @@ repeat:
* process'em.
*/
BUG_ON(!list_empty(&rescuer->scheduled));
- list_for_each_entry_safe(work, n, &gcwq->worklist, entry)
+ list_for_each_entry_safe(work, n, &pool->worklist, entry)
if (get_work_cwq(work) == cwq)
move_linked_works(work, scheduled, &n);
@@ -2072,8 +2212,8 @@ repeat:
* regular worker; otherwise, we end up with 0 concurrency
* and stalling the execution.
*/
- if (keep_working(gcwq))
- wake_up_worker(gcwq);
+ if (keep_working(pool))
+ wake_up_worker(pool);
spin_unlock_irq(&gcwq->lock);
}
@@ -2198,7 +2338,7 @@ static bool flush_workqueue_prep_cwqs(struct workqueue_struct *wq,
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
- struct global_cwq *gcwq = cwq->gcwq;
+ struct global_cwq *gcwq = cwq->pool->gcwq;
spin_lock_irq(&gcwq->lock);
@@ -2414,9 +2554,9 @@ reflush:
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
bool drained;
- spin_lock_irq(&cwq->gcwq->lock);
+ spin_lock_irq(&cwq->pool->gcwq->lock);
drained = !cwq->nr_active && list_empty(&cwq->delayed_works);
- spin_unlock_irq(&cwq->gcwq->lock);
+ spin_unlock_irq(&cwq->pool->gcwq->lock);
if (drained)
continue;
@@ -2456,7 +2596,7 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr,
*/
smp_rmb();
cwq = get_work_cwq(work);
- if (unlikely(!cwq || gcwq != cwq->gcwq))
+ if (unlikely(!cwq || gcwq != cwq->pool->gcwq))
goto already_gone;
} else if (wait_executing) {
worker = find_worker_executing_work(gcwq, work);
@@ -2970,13 +3110,6 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
if (flags & WQ_MEM_RECLAIM)
flags |= WQ_RESCUER;
- /*
- * Unbound workqueues aren't concurrency managed and should be
- * dispatched to workers immediately.
- */
- if (flags & WQ_UNBOUND)
- flags |= WQ_HIGHPRI;
-
max_active = max_active ?: WQ_DFL_ACTIVE;
max_active = wq_clamp_max_active(max_active, flags, name);
@@ -3001,9 +3134,10 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,
for_each_cwq_cpu(cpu, wq) {
struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq);
struct global_cwq *gcwq = get_gcwq(cpu);
+ int pool_idx = (bool)(flags & WQ_HIGHPRI);
BUG_ON((unsigned long)cwq & WORK_STRUCT_FLAG_MASK);
- cwq->gcwq = gcwq;
+ cwq->pool = &gcwq->pools[pool_idx];
cwq->wq = wq;
cwq->flush_color = -1;
cwq->max_active = max_active;
@@ -3214,369 +3348,143 @@ EXPORT_SYMBOL_GPL(work_busy);
* gcwqs serve mix of short, long and very long running works making
* blocked draining impractical.
*
- * This is solved by allowing a gcwq to be detached from CPU, running
- * it with unbound (rogue) workers and allowing it to be reattached
- * later if the cpu comes back online. A separate thread is created
- * to govern a gcwq in such state and is called the trustee of the
- * gcwq.
- *
- * Trustee states and their descriptions.
- *
- * START Command state used on startup. On CPU_DOWN_PREPARE, a
- * new trustee is started with this state.
- *
- * IN_CHARGE Once started, trustee will enter this state after
- * assuming the manager role and making all existing
- * workers rogue. DOWN_PREPARE waits for trustee to
- * enter this state. After reaching IN_CHARGE, trustee
- * tries to execute the pending worklist until it's empty
- * and the state is set to BUTCHER, or the state is set
- * to RELEASE.
- *
- * BUTCHER Command state which is set by the cpu callback after
- * the cpu has went down. Once this state is set trustee
- * knows that there will be no new works on the worklist
- * and once the worklist is empty it can proceed to
- * killing idle workers.
- *
- * RELEASE Command state which is set by the cpu callback if the
- * cpu down has been canceled or it has come online
- * again. After recognizing this state, trustee stops
- * trying to drain or butcher and clears ROGUE, rebinds
- * all remaining workers back to the cpu and releases
- * manager role.
- *
- * DONE Trustee will enter this state after BUTCHER or RELEASE
- * is complete.
- *
- * trustee CPU draining
- * took over down complete
- * START -----------> IN_CHARGE -----------> BUTCHER -----------> DONE
- * | | ^
- * | CPU is back online v return workers |
- * ----------------> RELEASE --------------
+ * This is solved by allowing a gcwq to be disassociated from the CPU
+ * running as an unbound one and allowing it to be reattached later if the
+ * cpu comes back online.
*/
-/**
- * trustee_wait_event_timeout - timed event wait for trustee
- * @cond: condition to wait for
- * @timeout: timeout in jiffies
- *
- * wait_event_timeout() for trustee to use. Handles locking and
- * checks for RELEASE request.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock) which may be released and regrabbed
- * multiple times. To be used by trustee.
- *
- * RETURNS:
- * Positive indicating left time if @cond is satisfied, 0 if timed
- * out, -1 if canceled.
- */
-#define trustee_wait_event_timeout(cond, timeout) ({ \
- long __ret = (timeout); \
- while (!((cond) || (gcwq->trustee_state == TRUSTEE_RELEASE)) && \
- __ret) { \
- spin_unlock_irq(&gcwq->lock); \
- __wait_event_timeout(gcwq->trustee_wait, (cond) || \
- (gcwq->trustee_state == TRUSTEE_RELEASE), \
- __ret); \
- spin_lock_irq(&gcwq->lock); \
- } \
- gcwq->trustee_state == TRUSTEE_RELEASE ? -1 : (__ret); \
-})
-
-/**
- * trustee_wait_event - event wait for trustee
- * @cond: condition to wait for
- *
- * wait_event() for trustee to use. Automatically handles locking and
- * checks for CANCEL request.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock) which may be released and regrabbed
- * multiple times. To be used by trustee.
- *
- * RETURNS:
- * 0 if @cond is satisfied, -1 if canceled.
- */
-#define trustee_wait_event(cond) ({ \
- long __ret1; \
- __ret1 = trustee_wait_event_timeout(cond, MAX_SCHEDULE_TIMEOUT);\
- __ret1 < 0 ? -1 : 0; \
-})
-
-static int __cpuinit trustee_thread(void *__gcwq)
+/* claim manager positions of all pools */
+static void gcwq_claim_management_and_lock(struct global_cwq *gcwq)
{
- struct global_cwq *gcwq = __gcwq;
- struct worker *worker;
- struct work_struct *work;
- struct hlist_node *pos;
- long rc;
- int i;
-
- BUG_ON(gcwq->cpu != smp_processor_id());
+ struct worker_pool *pool;
+ for_each_worker_pool(pool, gcwq)
+ mutex_lock_nested(&pool->manager_mutex, pool - gcwq->pools);
spin_lock_irq(&gcwq->lock);
- /*
- * Claim the manager position and make all workers rogue.
- * Trustee must be bound to the target cpu and can't be
- * cancelled.
- */
- BUG_ON(gcwq->cpu != smp_processor_id());
- rc = trustee_wait_event(!(gcwq->flags & GCWQ_MANAGING_WORKERS));
- BUG_ON(rc < 0);
-
- gcwq->flags |= GCWQ_MANAGING_WORKERS;
-
- list_for_each_entry(worker, &gcwq->idle_list, entry)
- worker->flags |= WORKER_ROGUE;
+}
- for_each_busy_worker(worker, i, pos, gcwq)
- worker->flags |= WORKER_ROGUE;
+/* release manager positions */
+static void gcwq_release_management_and_unlock(struct global_cwq *gcwq)
+{
+ struct worker_pool *pool;
- /*
- * Call schedule() so that we cross rq->lock and thus can
- * guarantee sched callbacks see the rogue flag. This is
- * necessary as scheduler callbacks may be invoked from other
- * cpus.
- */
spin_unlock_irq(&gcwq->lock);
- schedule();
- spin_lock_irq(&gcwq->lock);
+ for_each_worker_pool(pool, gcwq)
+ mutex_unlock(&pool->manager_mutex);
+}
- /*
- * Sched callbacks are disabled now. Zap nr_running. After
- * this, nr_running stays zero and need_more_worker() and
- * keep_working() are always true as long as the worklist is
- * not empty.
- */
- atomic_set(get_gcwq_nr_running(gcwq->cpu), 0);
+static void gcwq_unbind_fn(struct work_struct *work)
+{
+ struct global_cwq *gcwq = get_gcwq(smp_processor_id());
+ struct worker_pool *pool;
+ struct worker *worker;
+ struct hlist_node *pos;
+ int i;
- spin_unlock_irq(&gcwq->lock);
- del_timer_sync(&gcwq->idle_timer);
- spin_lock_irq(&gcwq->lock);
+ BUG_ON(gcwq->cpu != smp_processor_id());
- /*
- * We're now in charge. Notify and proceed to drain. We need
- * to keep the gcwq running during the whole CPU down
- * procedure as other cpu hotunplug callbacks may need to
- * flush currently running tasks.
- */
- gcwq->trustee_state = TRUSTEE_IN_CHARGE;
- wake_up_all(&gcwq->trustee_wait);
+ gcwq_claim_management_and_lock(gcwq);
/*
- * The original cpu is in the process of dying and may go away
- * anytime now. When that happens, we and all workers would
- * be migrated to other cpus. Try draining any left work. We
- * want to get it over with ASAP - spam rescuers, wake up as
- * many idlers as necessary and create new ones till the
- * worklist is empty. Note that if the gcwq is frozen, there
- * may be frozen works in freezable cwqs. Don't declare
- * completion while frozen.
+ * We've claimed all manager positions. Make all workers unbound
+ * and set DISASSOCIATED. Before this, all workers except for the
+ * ones which are still executing works from before the last CPU
+ * down must be on the cpu. After this, they may become diasporas.
*/
- while (gcwq->nr_workers != gcwq->nr_idle ||
- gcwq->flags & GCWQ_FREEZING ||
- gcwq->trustee_state == TRUSTEE_IN_CHARGE) {
- int nr_works = 0;
+ for_each_worker_pool(pool, gcwq)
+ list_for_each_entry(worker, &pool->idle_list, entry)
+ worker->flags |= WORKER_UNBOUND;
- list_for_each_entry(work, &gcwq->worklist, entry) {
- send_mayday(work);
- nr_works++;
- }
+ for_each_busy_worker(worker, i, pos, gcwq)
+ worker->flags |= WORKER_UNBOUND;
- list_for_each_entry(worker, &gcwq->idle_list, entry) {
- if (!nr_works--)
- break;
- wake_up_process(worker->task);
- }
+ gcwq->flags |= GCWQ_DISASSOCIATED;
- if (need_to_create_worker(gcwq)) {
- spin_unlock_irq(&gcwq->lock);
- worker = create_worker(gcwq, false);
- spin_lock_irq(&gcwq->lock);
- if (worker) {
- worker->flags |= WORKER_ROGUE;
- start_worker(worker);
- }
- }
-
- /* give a breather */
- if (trustee_wait_event_timeout(false, TRUSTEE_COOLDOWN) < 0)
- break;
- }
+ gcwq_release_management_and_unlock(gcwq);
/*
- * Either all works have been scheduled and cpu is down, or
- * cpu down has already been canceled. Wait for and butcher
- * all workers till we're canceled.
+ * Call schedule() so that we cross rq->lock and thus can guarantee
+ * sched callbacks see the %WORKER_UNBOUND flag. This is necessary
+ * as scheduler callbacks may be invoked from other cpus.
*/
- do {
- rc = trustee_wait_event(!list_empty(&gcwq->idle_list));
- while (!list_empty(&gcwq->idle_list))
- destroy_worker(list_first_entry(&gcwq->idle_list,
- struct worker, entry));
- } while (gcwq->nr_workers && rc >= 0);
+ schedule();
/*
- * At this point, either draining has completed and no worker
- * is left, or cpu down has been canceled or the cpu is being
- * brought back up. There shouldn't be any idle one left.
- * Tell the remaining busy ones to rebind once it finishes the
- * currently scheduled works by scheduling the rebind_work.
+ * Sched callbacks are disabled now. Zap nr_running. After this,
+ * nr_running stays zero and need_more_worker() and keep_working()
+ * are always true as long as the worklist is not empty. @gcwq now
+ * behaves as unbound (in terms of concurrency management) gcwq
+ * which is served by workers tied to the CPU.
+ *
+ * On return from this function, the current worker would trigger
+ * unbound chain execution of pending work items if other workers
+ * didn't already.
*/
- WARN_ON(!list_empty(&gcwq->idle_list));
-
- for_each_busy_worker(worker, i, pos, gcwq) {
- struct work_struct *rebind_work = &worker->rebind_work;
-
- /*
- * Rebind_work may race with future cpu hotplug
- * operations. Use a separate flag to mark that
- * rebinding is scheduled.
- */
- worker->flags |= WORKER_REBIND;
- worker->flags &= ~WORKER_ROGUE;
-
- /* queue rebind_work, wq doesn't matter, use the default one */
- if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
- work_data_bits(rebind_work)))
- continue;
-
- debug_work_activate(rebind_work);
- insert_work(get_cwq(gcwq->cpu, system_wq), rebind_work,
- worker->scheduled.next,
- work_color_to_flags(WORK_NO_COLOR));
- }
-
- /* relinquish manager role */
- gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
-
- /* notify completion */
- gcwq->trustee = NULL;
- gcwq->trustee_state = TRUSTEE_DONE;
- wake_up_all(&gcwq->trustee_wait);
- spin_unlock_irq(&gcwq->lock);
- return 0;
+ for_each_worker_pool(pool, gcwq)
+ atomic_set(get_pool_nr_running(pool), 0);
}
-/**
- * wait_trustee_state - wait for trustee to enter the specified state
- * @gcwq: gcwq the trustee of interest belongs to
- * @state: target state to wait for
- *
- * Wait for the trustee to reach @state. DONE is already matched.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock) which may be released and regrabbed
- * multiple times. To be used by cpu_callback.
+/*
+ * Workqueues should be brought up before normal priority CPU notifiers.
+ * This will be registered high priority CPU notifier.
*/
-static void __cpuinit wait_trustee_state(struct global_cwq *gcwq, int state)
-__releases(&gcwq->lock)
-__acquires(&gcwq->lock)
-{
- if (!(gcwq->trustee_state == state ||
- gcwq->trustee_state == TRUSTEE_DONE)) {
- spin_unlock_irq(&gcwq->lock);
- __wait_event(gcwq->trustee_wait,
- gcwq->trustee_state == state ||
- gcwq->trustee_state == TRUSTEE_DONE);
- spin_lock_irq(&gcwq->lock);
- }
-}
-
-static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
- unsigned long action,
- void *hcpu)
+static int __devinit workqueue_cpu_up_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
struct global_cwq *gcwq = get_gcwq(cpu);
- struct task_struct *new_trustee = NULL;
- struct worker *uninitialized_var(new_worker);
- unsigned long flags;
-
- action &= ~CPU_TASKS_FROZEN;
+ struct worker_pool *pool;
- switch (action) {
- case CPU_DOWN_PREPARE:
- new_trustee = kthread_create(trustee_thread, gcwq,
- "workqueue_trustee/%d\n", cpu);
- if (IS_ERR(new_trustee))
- return notifier_from_errno(PTR_ERR(new_trustee));
- kthread_bind(new_trustee, cpu);
- /* fall through */
+ switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
- BUG_ON(gcwq->first_idle);
- new_worker = create_worker(gcwq, false);
- if (!new_worker) {
- if (new_trustee)
- kthread_stop(new_trustee);
- return NOTIFY_BAD;
- }
- }
-
- /* some are called w/ irq disabled, don't disturb irq status */
- spin_lock_irqsave(&gcwq->lock, flags);
+ for_each_worker_pool(pool, gcwq) {
+ struct worker *worker;
- switch (action) {
- case CPU_DOWN_PREPARE:
- /* initialize trustee and tell it to acquire the gcwq */
- BUG_ON(gcwq->trustee || gcwq->trustee_state != TRUSTEE_DONE);
- gcwq->trustee = new_trustee;
- gcwq->trustee_state = TRUSTEE_START;
- wake_up_process(gcwq->trustee);
- wait_trustee_state(gcwq, TRUSTEE_IN_CHARGE);
- /* fall through */
- case CPU_UP_PREPARE:
- BUG_ON(gcwq->first_idle);
- gcwq->first_idle = new_worker;
- break;
+ if (pool->nr_workers)
+ continue;
- case CPU_DYING:
- /*
- * Before this, the trustee and all workers except for
- * the ones which are still executing works from
- * before the last CPU down must be on the cpu. After
- * this, they'll all be diasporas.
- */
- gcwq->flags |= GCWQ_DISASSOCIATED;
- break;
+ worker = create_worker(pool);
+ if (!worker)
+ return NOTIFY_BAD;
- case CPU_POST_DEAD:
- gcwq->trustee_state = TRUSTEE_BUTCHER;
- /* fall through */
- case CPU_UP_CANCELED:
- destroy_worker(gcwq->first_idle);
- gcwq->first_idle = NULL;
+ spin_lock_irq(&gcwq->lock);
+ start_worker(worker);
+ spin_unlock_irq(&gcwq->lock);
+ }
break;
case CPU_DOWN_FAILED:
case CPU_ONLINE:
+ gcwq_claim_management_and_lock(gcwq);
gcwq->flags &= ~GCWQ_DISASSOCIATED;
- if (gcwq->trustee_state != TRUSTEE_DONE) {
- gcwq->trustee_state = TRUSTEE_RELEASE;
- wake_up_process(gcwq->trustee);
- wait_trustee_state(gcwq, TRUSTEE_DONE);
- }
-
- /*
- * Trustee is done and there might be no worker left.
- * Put the first_idle in and request a real manager to
- * take a look.
- */
- spin_unlock_irq(&gcwq->lock);
- kthread_bind(gcwq->first_idle->task, cpu);
- spin_lock_irq(&gcwq->lock);
- gcwq->flags |= GCWQ_MANAGE_WORKERS;
- start_worker(gcwq->first_idle);
- gcwq->first_idle = NULL;
+ rebind_workers(gcwq);
+ gcwq_release_management_and_unlock(gcwq);
break;
}
+ return NOTIFY_OK;
+}
- spin_unlock_irqrestore(&gcwq->lock, flags);
+/*
+ * Workqueues should be brought down after normal priority CPU notifiers.
+ * This will be registered as low priority CPU notifier.
+ */
+static int __devinit workqueue_cpu_down_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct work_struct unbind_work;
- return notifier_from_errno(0);
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DOWN_PREPARE:
+ /* unbinding should happen on the local CPU */
+ INIT_WORK_ONSTACK(&unbind_work, gcwq_unbind_fn);
+ schedule_work_on(cpu, &unbind_work);
+ flush_work(&unbind_work);
+ break;
+ }
+ return NOTIFY_OK;
}
#ifdef CONFIG_SMP
@@ -3735,6 +3643,7 @@ void thaw_workqueues(void)
for_each_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker_pool *pool;
struct workqueue_struct *wq;
spin_lock_irq(&gcwq->lock);
@@ -3756,7 +3665,8 @@ void thaw_workqueues(void)
cwq_activate_first_delayed(cwq);
}
- wake_up_worker(gcwq);
+ for_each_worker_pool(pool, gcwq)
+ wake_up_worker(pool);
spin_unlock_irq(&gcwq->lock);
}
@@ -3772,46 +3682,57 @@ static int __init init_workqueues(void)
unsigned int cpu;
int i;
- cpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE);
+ cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
+ cpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);
/* initialize gcwqs */
for_each_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
+ struct worker_pool *pool;
spin_lock_init(&gcwq->lock);
- INIT_LIST_HEAD(&gcwq->worklist);
gcwq->cpu = cpu;
gcwq->flags |= GCWQ_DISASSOCIATED;
- INIT_LIST_HEAD(&gcwq->idle_list);
for (i = 0; i < BUSY_WORKER_HASH_SIZE; i++)
INIT_HLIST_HEAD(&gcwq->busy_hash[i]);
- init_timer_deferrable(&gcwq->idle_timer);
- gcwq->idle_timer.function = idle_worker_timeout;
- gcwq->idle_timer.data = (unsigned long)gcwq;
+ for_each_worker_pool(pool, gcwq) {
+ pool->gcwq = gcwq;
+ INIT_LIST_HEAD(&pool->worklist);
+ INIT_LIST_HEAD(&pool->idle_list);
+
+ init_timer_deferrable(&pool->idle_timer);
+ pool->idle_timer.function = idle_worker_timeout;
+ pool->idle_timer.data = (unsigned long)pool;
- setup_timer(&gcwq->mayday_timer, gcwq_mayday_timeout,
- (unsigned long)gcwq);
+ setup_timer(&pool->mayday_timer, gcwq_mayday_timeout,
+ (unsigned long)pool);
- ida_init(&gcwq->worker_ida);
+ mutex_init(&pool->manager_mutex);
+ ida_init(&pool->worker_ida);
+ }
- gcwq->trustee_state = TRUSTEE_DONE;
- init_waitqueue_head(&gcwq->trustee_wait);
+ init_waitqueue_head(&gcwq->rebind_hold);
}
/* create the initial worker */
for_each_online_gcwq_cpu(cpu) {
struct global_cwq *gcwq = get_gcwq(cpu);
- struct worker *worker;
+ struct worker_pool *pool;
if (cpu != WORK_CPU_UNBOUND)
gcwq->flags &= ~GCWQ_DISASSOCIATED;
- worker = create_worker(gcwq, true);
- BUG_ON(!worker);
- spin_lock_irq(&gcwq->lock);
- start_worker(worker);
- spin_unlock_irq(&gcwq->lock);
+
+ for_each_worker_pool(pool, gcwq) {
+ struct worker *worker;
+
+ worker = create_worker(pool);
+ BUG_ON(!worker);
+ spin_lock_irq(&gcwq->lock);
+ start_worker(worker);
+ spin_unlock_irq(&gcwq->lock);
+ }
}
system_wq = alloc_workqueue("events", 0, 0);
diff --git a/mm/failslab.c b/mm/failslab.c
index 0dd7b8fec71c..49598688c44f 100644
--- a/mm/failslab.c
+++ b/mm/failslab.c
@@ -5,14 +5,29 @@ static struct {
struct fault_attr attr;
u32 ignore_gfp_wait;
int cache_filter;
+ u32 size;
} failslab = {
.attr = FAULT_ATTR_INITIALIZER,
.ignore_gfp_wait = 1,
.cache_filter = 0,
+ .size = 0,
};
+static void fail_dump(struct fault_attr *attr)
+{
+ if (attr->verbose > 0)
+ printk(KERN_NOTICE "FAULT_INJECTION: forcing a failure\n");
+ if (attr->verbose > 1)
+ dump_stack();
+}
+
bool should_failslab(size_t size, gfp_t gfpflags, unsigned long cache_flags)
{
+ if (failslab.size && size > failslab.size) {
+ fail_dump(&failslab.attr);
+ return true;
+ }
+
if (gfpflags & __GFP_NOFAIL)
return false;
@@ -48,6 +63,10 @@ static int __init failslab_debugfs_init(void)
&failslab.cache_filter))
goto fail;
+ if (!debugfs_create_u32("size", mode, dir,
+ &failslab.size))
+ goto fail;
+
return 0;
fail:
debugfs_remove_recursive(dir);
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index d897278b1f97..6a3ee981931d 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -104,7 +104,7 @@ as-option = $(call try-run,\
# Usage: cflags-y += $(call as-instr,instr,option1,option2)
as-instr = $(call try-run,\
- /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
+ printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 4d403844e137..57d31182d3f9 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -45,26 +45,9 @@ scm_version()
# Check for git and a git repo.
if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
- # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
- # it, because this version is defined in the top level Makefile.
- if [ -z "`git describe --exact-match 2>/dev/null`" ]; then
-
- # If only the short version is requested, don't bother
- # running further git commands
- if $short; then
- echo "+"
- return
- fi
- # If we are past a tagged commit (like
- # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
- if atag="`git describe 2>/dev/null`"; then
- echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
-
- # If we don't have a tag at all we print -g{commitish}.
- else
- printf '%s%s' -g $head
- fi
- fi
+ # Regardless whether it is a tagged commit (like "v2.6.30-rc6"),
+ # we will put the commit info in.
+ printf '%s%s' -g $head
# Is this git on svn?
if git config --get svn-remote.svn.url >/dev/null; then
diff --git a/security/tf_driver/s_version.h b/security/tf_driver/s_version.h
index d812cdca75df..2ed6210cf231 100644
--- a/security/tf_driver/s_version.h
+++ b/security/tf_driver/s_version.h
@@ -38,7 +38,7 @@
/*
* This version number must be updated for each new release
*/
-#define S_VERSION_MAIN "01.08"
+#define S_VERSION_MAIN "01.16"
/*
* If this is a patch or engineering version use the following
diff --git a/security/tf_driver/tf_protocol.h b/security/tf_driver/tf_protocol.h
index b264f04c4454..e39842bd6e16 100644
--- a/security/tf_driver/tf_protocol.h
+++ b/security/tf_driver/tf_protocol.h
@@ -659,7 +659,7 @@ struct tf_l1_shared_buffer {
#ifdef CONFIG_TF_ZEBRA
u8 rpc_trace_buffer[140];
u8 rpc_cus_buffer[180];
- #elif CONFIG_SECURE_TRACES
+ #elif defined(CONFIG_SECURE_TRACES)
u32 traces_status;
u8 traces_buffer[140];
u8 reserved3[176];
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 91b2e4689175..ff10a630da92 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2840,6 +2840,16 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
return change;
}
+int snd_hda_max_pcm_ch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xFFFFFFFF;
+ return 0;
+}
+
int snd_hda_hdmi_decode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -2850,6 +2860,15 @@ int snd_hda_hdmi_decode_info(struct snd_kcontrol *kcontrol,
return 0;
}
+static int snd_hda_max_pcm_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ucontrol->value.integer.value[0] = codec->max_pcm_channels;
+ return 0;
+}
+
static int snd_hda_hdmi_decode_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -2894,6 +2913,12 @@ static struct snd_kcontrol_new dig_mixes[] = {
.info = snd_hda_hdmi_decode_info,
.get = snd_hda_hdmi_decode_get,
},
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HDA Maximum PCM Channels",
+ .info = snd_hda_max_pcm_ch_info,
+ .get = snd_hda_max_pcm_ch_get,
+ },
{ } /* end */
};
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 1c5dc6d73d6b..6cba73ce1997 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -868,6 +868,7 @@ struct hda_codec {
#endif
unsigned int recv_dec_cap;
+ unsigned int max_pcm_channels;
/* codec-specific additional proc output */
void (*proc_widget_hook)(struct snd_info_buffer *buffer,
struct hda_codec *codec, hda_nid_t nid);
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index a8042e14f5de..862dd35260d0 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -427,6 +427,10 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld,
codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_AC3);
} else if (eld->sad[i].format == AUDIO_CODING_TYPE_DTS) {
codec->recv_dec_cap |= (1 << AUDIO_CODING_TYPE_DTS);
+ } else if (eld->sad[i].format == AUDIO_CODING_TYPE_LPCM) {
+ codec->max_pcm_channels =
+ eld->sad[i].channels > codec->max_pcm_channels ?
+ eld->sad[i].channels : codec->max_pcm_channels;
}
}
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7d5a66122eec..8946925ae41a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -256,6 +256,7 @@ config SND_SOC_TLV320AIC3X
tristate
config SND_SOC_TLV320AIC326X
+ select AIC3262_CODEC
tristate "TI AIC326x Codec"
config SND_SOC_TLV320DAC33
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index d80b7bbff2e8..dc89ee430031 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -35,7 +35,8 @@ 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
+snd-soc-tlv320aic326x-objs := tlv320aic326x.o aic3xxx_cfw_ops.o
+snd-soc-tlv320aic326x-objs += aic3262_codec_ops.o aic326x_tiload.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/aic3262_codec_ops.c b/sound/soc/codecs/aic3262_codec_ops.c
new file mode 100644
index 000000000000..45686c7aa460
--- /dev/null
+++ b/sound/soc/codecs/aic3262_codec_ops.c
@@ -0,0 +1,424 @@
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/mfd/tlv320aic3262-core.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#include <sound/soc.h>
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+#include "tlv320aic326x.h"
+#include "aic3262_codec_ops.h"
+
+int aic3262_ops_reg_read(void *p, unsigned int reg)
+{
+ struct aic3262_priv *ps = p;
+ union cfw_register *c = (union cfw_register *) &reg;
+ union aic326x_reg_union mreg;
+
+ mreg.aic326x_register.offset = c->offset;
+ mreg.aic326x_register.page = c->page;
+ mreg.aic326x_register.book = c->book;
+ mreg.aic326x_register.reserved = 0;
+
+ return aic3262_reg_read(ps->codec->control_data,
+ mreg.aic326x_register_int);
+
+}
+int aic3262_ops_reg_write(void *p, unsigned int reg, unsigned char mval)
+{
+ struct aic3262_priv *ps = p;
+ union aic326x_reg_union mreg;
+ union cfw_register *c = (union cfw_register *) &reg;
+
+ mreg.aic326x_register.offset = c->offset;
+ mreg.aic326x_register.page = c->page;
+ mreg.aic326x_register.book = c->book;
+ mreg.aic326x_register.reserved = 0;
+ mval = c->data;
+ DBG("reg_write:page %d book %d offset %d mval : %#x\n",
+ mreg.aic326x_register.page, mreg.aic326x_register.book,
+ mreg.aic326x_register.offset, mval);
+ return aic3262_reg_write(ps->codec->control_data,
+ mreg.aic326x_register_int, mval);
+}
+
+int aic3262_ops_set_bits(void *p, unsigned int reg,
+ unsigned char mask, unsigned char val)
+{
+ struct aic3262_priv *ps = p;
+
+ union aic326x_reg_union mreg;
+ union cfw_register *c = (union cfw_register *) &reg;
+ mreg.aic326x_register.offset = c->offset;
+ mreg.aic326x_register.page = c->page;
+ mreg.aic326x_register.book = c->book;
+ mreg.aic326x_register.reserved = 0;
+ DBG("set_bits:page %d book %d offset %d mask %#x val %#x\n",
+ mreg.aic326x_register.page, mreg.aic326x_register.book,
+ mreg.aic326x_register.offset, mask, val);
+
+ return aic3262_set_bits(ps->codec->control_data,
+ mreg.aic326x_register_int, mask, val);
+
+}
+
+int aic3262_ops_bulk_read(void *p, unsigned int reg, int count, u8 *buf)
+{
+ struct aic3262_priv *ps = p;
+
+ union aic326x_reg_union mreg;
+ union cfw_register *c = (union cfw_register *) &reg;
+ mreg.aic326x_register.offset = c->offset;
+ mreg.aic326x_register.page = c->page;
+ mreg.aic326x_register.book = c->book;
+ mreg.aic326x_register.reserved = 0;
+
+ return aic3262_bulk_read(ps->codec->control_data,
+ mreg.aic326x_register_int, count, buf);
+}
+
+int aic3262_ops_bulk_write(void *p, unsigned int reg, int count, const u8 *buf)
+{
+ struct aic3262_priv *ps = p;
+ union aic326x_reg_union mreg;
+ union cfw_register *c = (union cfw_register *) &reg;
+
+ mreg.aic326x_register.offset = c->offset;
+ mreg.aic326x_register.page = c->page;
+ mreg.aic326x_register.book = c->book;
+ mreg.aic326x_register.reserved = 0;
+ DBG("bulk_write: ncmd %d page %d book %d offset %d data[0] %d\n",
+ count, mreg.aic326x_register.page, mreg.aic326x_register.book,
+ mreg.aic326x_register.offset, buf[0]);
+
+ return aic3262_bulk_write(ps->codec->control_data,
+ mreg.aic326x_register_int, count, buf);
+}
+/*****************************************************************************
+Function Name : aic3262_ops_dlock_lock
+Argument : pointer argument to the codec
+Return value : Integer
+Purpose : To Read the run state of the DAC and ADC
+by reading the codec and returning the run state
+
+Run state Bit format
+
+------------------------------------------------------
+D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 |
+R R R LADC RADC R R LDAC RDAC
+------------------------------------------------------
+
+*******************************************************************************/
+
+int aic3262_ops_lock(void *pv)
+{
+ int run_state = 0;
+ struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;
+ mutex_lock(&aic3262->codec->mutex);
+
+ /* Reading the run state of adc and dac */
+ run_state = get_runstate(aic3262->codec->control_data);
+
+ return run_state;
+}
+/*******************************************************************************
+Function name : aic3262_ops_dlock_unlock
+Argument : pointer argument to the codec
+Return Value : integer returning 0
+Purpose : To unlock the mutex acqiured for reading
+run state of the codec
+ ******************************************************************************/
+int aic3262_ops_unlock(void *pv)
+{
+ /*Releasing the lock of mutex */
+ struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;
+
+ mutex_unlock(&aic3262->codec->mutex);
+ return 0;
+}
+/*******************************************************************************
+Function Name : aic3262_ops_dlock_stop
+Argument : pointer Argument to the codec
+mask tells us the bit format of the
+codec running state
+
+Bit Format:
+------------------------------------------------------
+D31|..........| D7 | D6| D5 | D4 | D3 | D2 | D1 | D0 |
+R R R AL AR R R DL DR
+------------------------------------------------------
+R - Reserved
+A - minidsp_A
+D - minidsp_D
+ ******************************************************************************/
+int aic3262_ops_stop(void *pv, int mask)
+{
+ int run_state = 0;
+ int limask = 0;
+ struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;
+ int ret_wbits = 0;
+
+ mutex_lock(&aic3262->codec->mutex);
+ run_state = get_runstate(aic3262->codec->control_data);
+
+ limask = mask & AIC3XX_COPS_MDSP_A;
+ if (limask != 0)
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_ADC_DATAPATH_SETUP, 0xC0, 0);
+
+ limask = mask & AIC3XX_COPS_MDSP_D;
+ if (limask != 0)
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_DAC_DATAPATH_SETUP, 0xC0, 0);
+
+ limask = mask & AIC3XX_COPS_MDSP_A;
+ if (limask != 0) {
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK,
+ 0, TIME_DELAY, DELAY_COUNTER);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "at line %d function %s, ADC powerdown"
+ "wait_bits timedout\n",
+ __LINE__, __func__);
+ }
+
+ limask = mask & AIC3XX_COPS_MDSP_D;
+ if (limask != 0) {
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK,
+ 0, TIME_DELAY, DELAY_COUNTER);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "at line %d function %s, DAC powerdown"
+ "wait_bits timedout\n",
+ __LINE__, __func__);
+ }
+
+ return run_state;
+
+}
+/****************************************************************************
+Function name : aic3262_ops_dlock_restore
+Argument : pointer argument to the codec,run_state
+Return Value : integer returning 0
+Purpose : To unlock the mutex acqiured for reading
+run state of the codec and to restore the states of the dsp
+******************************************************************************/
+int aic3262_ops_restore(void *pv, int run_state)
+{
+ int sync_state;
+ struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;
+
+ /* This is for read the sync mode register state */
+ sync_state = SYNC_STATE(aic3262);
+
+ /*checking whether the sync mode has been set or
+ not and checking the current state */
+ if (((run_state & 0x30) && (run_state & 0x03)) && (sync_state & 0x80))
+ aic3262_restart_dsps_sync(pv, run_state);
+ else
+ aic3262_dsp_pwrup(pv, run_state);
+
+ mutex_unlock(&aic3262->codec->mutex);
+
+ return 0;
+}
+
+/*****************************************************************************
+Function name : aic3262_ops_adaptivebuffer_swap
+Argument : pointer argument to the codec,mask tells us which dsp has to
+be chosen for swapping
+Return Value : integer returning 0
+Purpose : To swap the coefficient buffers of minidsp according to mask
+******************************************************************************/
+
+int aic3262_ops_adaptivebuffer_swap(void *pv, int mask)
+{
+ struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;
+ int ret_wbits = 0;
+
+ if (mask & AIC3XX_ABUF_MDSP_A) {
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_ADC_ADAPTIVE_CRAM_REG, 0x1, 0x1);
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_ADC_ADAPTIVE_CRAM_REG, 0x1, 0, 15,
+ 1);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "at line %d function %s, miniDSP_A buffer swap failed\n",
+ __LINE__, __func__);
+ }
+
+ if (mask & AIC3XX_ABUF_MDSP_D1) {
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_DAC_ADAPTIVE_BANK1_REG, 0x1, 0x1);
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_DAC_ADAPTIVE_BANK1_REG, 0x1, 0,
+ 15, 1);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "at line %d function %s, miniDSP_D buffer1 swap failed\n",
+ __LINE__, __func__);
+ }
+
+ if (mask & AIC3XX_ABUF_MDSP_D2) {
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_DAC_ADAPTIVE_BANK2_REG, 0x1, 0x1);
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_DAC_ADAPTIVE_BANK2_REG, 0x1, 0,
+ 15, 1);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "at line %d function %s, miniDSP_D buffer2 swap failed\n",
+ __LINE__, __func__);
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+Function name : get_runstate
+Argument : pointer argument to the codec
+Return Value : integer returning the runstate
+Purpose : To read the current state of the dac's and adc's
+******************************************************************************/
+
+int get_runstate(void *ps)
+{
+ struct aic3262 *pr = ps;
+ int run_state = 0;
+ int DAC_state = 0, ADC_state = 0;
+ /* Read the run state */
+ DAC_state = aic3262_reg_read(pr, AIC3262_DAC_FLAG);
+ ADC_state = aic3262_reg_read(pr, AIC3262_ADC_FLAG);
+
+ DSP_STATUS(run_state, ADC_state, 6, 5);
+ DSP_STATUS(run_state, ADC_state, 2, 4);
+ DSP_STATUS(run_state, DAC_state, 7, 1);
+ DSP_STATUS(run_state, DAC_state, 3, 0);
+
+ return run_state;
+
+}
+/****************************************************************************
+Function name : aic3262_dsp_pwrdwn_status
+Argument : pointer argument to the codec , cur_state of dac's and adc's
+Return Value : integer returning 0
+Purpose : To read the status of dsp's
+******************************************************************************/
+
+int aic3262_dsp_pwrdwn_status(void *pv)
+{
+ struct aic3262_priv *aic3262 = pv;
+ int ret_wbits = 0;
+
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_ADC_DATAPATH_SETUP, 0XC0, 0);
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_DAC_DATAPATH_SETUP, 0XC0, 0);
+
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data, AIC3262_ADC_FLAG,
+ AIC3262_ADC_POWER_MASK, 0, TIME_DELAY,
+ DELAY_COUNTER);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev, "ADC Power down timedout\n");
+
+ aic3262_wait_bits(aic3262->codec->control_data, AIC3262_DAC_FLAG,
+ AIC3262_DAC_POWER_MASK, 0, TIME_DELAY, DELAY_COUNTER);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev, "DAC Power down timedout\n");
+
+ return 0;
+}
+
+int aic3262_dsp_pwrup(void *pv, int state)
+{
+ struct aic3262_priv *aic3262 = (struct aic3262_priv *)pv;
+ int adc_reg_mask = 0;
+ int adc_power_mask = 0;
+ int dac_reg_mask = 0;
+ int dac_power_mask = 0;
+ int ret_wbits;
+
+ if (state & AIC3262_COPS_MDSP_A_L) {
+ adc_reg_mask |= 0x80;
+ adc_power_mask |= AIC3262_LADC_POWER_MASK;
+ }
+ if (state & AIC3262_COPS_MDSP_A_R) {
+ adc_reg_mask |= 0x40;
+ adc_power_mask |= AIC3262_RADC_POWER_MASK;
+ }
+
+ if (state & AIC3262_COPS_MDSP_A)
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_ADC_DATAPATH_SETUP, 0XC0,
+ adc_reg_mask);
+
+ if (state & AIC3262_COPS_MDSP_D_L) {
+ dac_reg_mask |= 0x80;
+ dac_power_mask |= AIC3262_LDAC_POWER_MASK;
+ }
+ if (state & AIC3262_COPS_MDSP_D_R) {
+ dac_reg_mask |= 0x40;
+ dac_power_mask |= AIC3262_RDAC_POWER_MASK;
+ }
+
+ if (state & AIC3262_COPS_MDSP_D)
+ aic3262_set_bits(aic3262->codec->control_data,
+ AIC3262_DAC_DATAPATH_SETUP, 0XC0,
+ dac_reg_mask);
+
+ if (state & AIC3262_COPS_MDSP_A) {
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_ADC_FLAG, AIC3262_ADC_POWER_MASK,
+ adc_power_mask, TIME_DELAY,
+ DELAY_COUNTER);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "ADC Power down timedout\n");
+ }
+
+ if (state & AIC3262_COPS_MDSP_D) {
+ ret_wbits =
+ aic3262_wait_bits(aic3262->codec->control_data,
+ AIC3262_DAC_FLAG, AIC3262_DAC_POWER_MASK,
+ dac_power_mask, TIME_DELAY,
+ DELAY_COUNTER);
+ if (!ret_wbits)
+ dev_err(aic3262->codec->dev,
+ "ADC Power down timedout\n");
+ }
+
+ return 0;
+}
+
+int aic3262_restart_dsps_sync(void *pv, int run_state)
+{
+
+ aic3262_dsp_pwrdwn_status(pv);
+ aic3262_dsp_pwrup(pv, run_state);
+
+ return 0;
+}
+
+const struct aic3xxx_codec_ops aic3262_cfw_codec_ops = {
+ .reg_read = aic3262_ops_reg_read,
+ .reg_write = aic3262_ops_reg_write,
+ .set_bits = aic3262_ops_set_bits,
+ .bulk_read = aic3262_ops_bulk_read,
+ .bulk_write = aic3262_ops_bulk_write,
+ .lock = aic3262_ops_lock,
+ .unlock = aic3262_ops_unlock,
+ .stop = aic3262_ops_stop,
+ .restore = aic3262_ops_restore,
+ .bswap = aic3262_ops_adaptivebuffer_swap,
+};
+
diff --git a/sound/soc/codecs/aic3262_codec_ops.h b/sound/soc/codecs/aic3262_codec_ops.h
new file mode 100644
index 000000000000..bec0dc817e34
--- /dev/null
+++ b/sound/soc/codecs/aic3262_codec_ops.h
@@ -0,0 +1,44 @@
+#define SYNC_STATE(p) aic3262_reg_read(p->codec->control_data, AIC3262_DAC_PRB)
+
+#define DSP_STATUS(rs, adc_dac, rpos, rspos) (rs |= \
+ (((adc_dac>>rpos) & 1) << rspos))
+
+#define AIC3262_COPS_MDSP_A 0x30
+#define AIC3262_COPS_MDSP_A_L 0x20
+#define AIC3262_COPS_MDSP_A_R 0x10
+
+#define AIC3262_COPS_MDSP_D 0x03
+#define AIC3262_COPS_MDSP_D_L 0x02
+#define AIC3262_COPS_MDSP_D_R 0x01
+
+int get_runstate(void *);
+
+int aic3262_dsp_pwrup(void *, int);
+
+int aic3262_pwr_down(void *, int, int, int, int);
+
+int aic3262_dsp_pwrdwn_status(void *);
+
+int aic3262_ops_reg_read(void *p, unsigned int reg);
+
+int aic3262_ops_reg_write(void *p, unsigned int reg, unsigned char mval);
+
+int aic3262_ops_set_bits(void *p, unsigned int reg, unsigned char mask,
+ unsigned char val);
+
+int aic3262_ops_bulk_read(void *p, unsigned int reg, int count, u8 *buf);
+
+int aic3262_ops_bulk_write(void *p, unsigned int reg, int count,
+ const u8 *buf);
+
+int aic3262_ops_lock(void *pv);
+
+int aic3262_ops_unlock(void *pv);
+
+int aic3262_ops_stop(void *pv, int mask);
+
+int aic3262_ops_restore(void *pv, int run_state);
+
+int aic3262_ops_adaptivebuffer_swap(void *pv, int mask);
+
+int aic3262_restart_dsps_sync(void *pv, int run_state);
diff --git a/sound/soc/codecs/aic326x_tiload.c b/sound/soc/codecs/aic326x_tiload.c
index 07615dc5ebd7..781a6cb3456e 100644
--- a/sound/soc/codecs/aic326x_tiload.c
+++ b/sound/soc/codecs/aic326x_tiload.c
@@ -16,9 +16,9 @@
*
* History:
*
- * Rev 0.1 Tiload support 16-09-2010
+ * Rev 0.1 Tiload support TI 16-09-2010
*
- * The Tiload programming support is added to AIC3262.
+ * The Tiload programming support is added to AIC3262.
*
*/
@@ -37,16 +37,21 @@
#include <linux/platform_device.h>
#include <sound/soc.h>
#include <sound/control.h>
+#include <linux/switch.h>
+#include <sound/jack.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/tlv320aic3262-core.h>
#include "tlv320aic326x.h"
#include "aic326x_tiload.h"
/* enable debug prints in the driver */
-#define DEBUG
-//#undef DEBUG
+/*#define DEBUG */
+#undef DEBUG
#ifdef DEBUG
-#define dprintk(x...) printk(x)
+#define dprintk(x...) printk(x)
#else
#define dprintk(x...)
#endif
@@ -58,17 +63,12 @@
static void aic3262_dump_page(struct i2c_client *i2c, u8 page);
#endif
-/* 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, unsigned int reg,
- unsigned int value);
-int aic3262_driver_init(struct snd_soc_codec *codec);
/************** Dynamic aic3262 driver, TI LOAD support ***************/
static struct cdev *aic3262_cdev;
-static int aic3262_major = 0; /* Dynamic allocation of Mjr No. */
-static int aic3262_opened = 0; /* Dynamic allocation of Mjr No. */
+static union aic326x_reg_union aic_reg;
+static int aic3262_major; /* Dynamic allocation of Mjr No. */
+static int aic3262_opened; /* Dynamic allocation of Mjr No. */
static struct snd_soc_codec *aic3262_codec;
struct class *tiload_class;
static unsigned int magic_num = 0xE0;
@@ -77,10 +77,12 @@ static unsigned int magic_num = 0xE0;
#ifdef REG_DUMP_aic3262
/*
- *----------------------------------------------------------------------------
- * Function : aic3262_dump_page
- * Purpose : Read and display one codec register page, for debugging purpose
- *----------------------------------------------------------------------------
+ * aic3262_dump_page: Read and display one codec register page, for
+ debugging purpose
+ * @i2c; i2c_client identifies a single device (i.e. aic3262) connected
+ to an i2c bus.
+ * @page: page number
+ *
*/
static void aic3262_dump_page(struct i2c_client *i2c, u8 page)
{
@@ -88,103 +90,99 @@ static void aic3262_dump_page(struct i2c_client *i2c, u8 page)
u8 data;
u8 test_page_array[8];
- dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
- aic3262_change_page(codec, page);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
data = 0x0;
-
i2c_master_send(i2c, data, 1);
i2c_master_recv(i2c, test_page_array, 8);
- printk("\n------- aic3262 PAGE %d DUMP --------\n", page);
- for (i = 0; i < 8; i++) {
- printk(" [ %d ] = 0x%x\n", i, test_page_array[i]);
- }
+ dprintk("\n------- aic3262 PAGE %d DUMP --------\n", page);
+ for (i = 0; i < 8; i++)
+ dprintk(" [ %d ] = 0x%x\n", i, test_page_array[i]);
}
#endif
-/*
- *----------------------------------------------------------------------------
- * Function : tiload_open
+/**
+ * tiload_open: open method for aic3262-tiload programming interface
+ * @in: Pointer to inode
+ * @filp: pointer to file
*
- * Purpose : open method for aic3262-tiload programming interface
- *----------------------------------------------------------------------------
+ * Return: Return 0 if success.
*/
static int tiload_open(struct inode *in, struct file *filp)
{
- dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
if (aic3262_opened) {
- printk("%s device is already opened\n", "aic3262");
- printk("%s: only one instance of driver is allowed\n",
- "aic3262");
+ dprintk("%s device is already opened\n", "aic3262");
+ dprintk("%s: only one instance of driver is allowed\n",
+ "aic3262");
return -1;
}
aic3262_opened++;
return 0;
}
-/*
- *----------------------------------------------------------------------------
- * Function : tiload_release
+/**
+ * tiload_release close method for aic3262_tilaod programming interface
+ * @in: Pointer to inode
+ * @filp: pointer to file
*
- * Purpose : close method for aic3262_tilaod programming interface
- *----------------------------------------------------------------------------
+ * Return: Return 0 if success.
*/
static int tiload_release(struct inode *in, struct file *filp)
{
- dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
aic3262_opened--;
return 0;
}
-/*
- *----------------------------------------------------------------------------
- * Function : tiload_read
+/**
+ * tiload_read: read method for mini dsp programming interface
+ * @file: pointer to file
+ * @buf: pointer to user
+ * @count: number of byte to be read
+ * @offset: offset address
*
- * Purpose : read method for mini dsp programming interface
- *----------------------------------------------------------------------------
+ * Return: return value read
*/
-static ssize_t tiload_read(struct file *file, char __user * buf,
- size_t count, loff_t * offset)
+static ssize_t tiload_read(struct file *file, char __user *buf,
+ size_t count, loff_t *offset)
{
- static char rd_data[8];
+ static char rd_data[128];
char reg_addr;
size_t size;
- #ifdef DEBUG
+#ifdef DEBUG
int i;
- #endif
- struct i2c_client *i2c = aic3262_codec->control_data;
+#endif
+ struct aic3262 *control = aic3262_codec->control_data;
- dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
if (count > 128) {
- printk("Max 128 bytes can be read\n");
+ dprintk("Max 128 bytes can be read\n");
count = 128;
}
/* copy register address from user space */
size = copy_from_user(&reg_addr, buf, 1);
if (size != 0) {
- printk("read: copy_from_user failure\n");
+ dprintk("read: copy_from_user failure\n");
return -1;
}
/* Send the address to device thats is to be read */
- if (i2c_master_send(i2c, &reg_addr, 1) != 1) {
- dprintk("Can not write register address\n");
- return -1;
- }
- /* read the codec device registers */
- size = i2c_master_recv(i2c, rd_data, count);
+ aic_reg.aic326x_register.offset = reg_addr;
+ size =
+ aic3262_bulk_read(control, aic_reg.aic326x_register_int, count,
+ rd_data);
+
#ifdef DEBUG
- printk(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n",
- (int)size, reg_addr, (int)count);
- for (i = 0; i < (int)size; i++) {
- printk(KERN_ERR "rd_data[%d]=%x\n", i, rd_data[i]);
- }
+ pr_err(KERN_ERR "read size = %d, reg_addr= %x , count = %d\n",
+ (int)size, reg_addr, (int)count);
+ for (i = 0; i < (int)size; i++)
+ dprintk("rd_data[%d]=%x\n", i, rd_data[i]);
#endif
- if (size != count) {
- printk("read %d registers from the codec\n", size);
- }
+ if (size != count)
+ dprintk("read %d registers from the codec\n", size);
if (copy_to_user(buf, rd_data, size) != 0) {
dprintk("copy_to_user failed\n");
@@ -194,58 +192,71 @@ static ssize_t tiload_read(struct file *file, char __user * buf,
return size;
}
-/*
- *----------------------------------------------------------------------------
- * Function : tiload_write
+/**
+ * tiload_write: write method for aic3262_tiload programming interface
+ * @file: pointer to file
+ * @buf: pointer to user
+ * @count: number of byte to be read
+ * @offset: offset address
*
- * Purpose : write method for aic3262_tiload programming interface
- *----------------------------------------------------------------------------
+ * Return: return byte written
*/
-static ssize_t tiload_write(struct file *file, const char __user * buf,
- size_t count, loff_t * offset)
+static ssize_t tiload_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *offset)
{
- static char wr_data[8];
- u8 pg_no;
- #ifdef DEBUG
+ static char wr_data[128];
+#ifdef DEBUG
int i;
- #endif
- struct i2c_client *i2c = aic3262_codec->control_data;
- struct aic3262_priv *aic3262_private = snd_soc_codec_get_drvdata(aic3262_codec);
+#endif
+ struct aic3262 *control = aic3262_codec->control_data;
- dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
/* copy buffer from user space */
if (copy_from_user(wr_data, buf, count)) {
- printk("copy_from_user failure\n");
+ dprintk("copy_from_user failure\n");
return -1;
}
#ifdef DEBUG
- printk(KERN_ERR "write size = %d\n", (int)count);
- for (i = 0; i < (int)count; i++) {
- printk(KERN_INFO "\nwr_data[%d]=%x\n", i, wr_data[i]);
- }
+ dprintk("write size = %d\n", (int)count);
+ for (i = 0; i < (int)count; i++)
+ dprintk("\nwr_data[%d]=%x\n", i, wr_data[i]);
#endif
if (wr_data[0] == 0) {
- aic3262_change_page(aic3262_codec, wr_data[1]);
+ /*change of page seen, but will only be registered */
+ aic_reg.aic326x_register.page = wr_data[1];
+ return count;
+
+ } else
+ if (wr_data[0] == 127) {
+ /* change of book seen, but will not be sent for I2C write */
+ aic_reg.aic326x_register.book = wr_data[1];
return count;
- }
- pg_no = aic3262_private->page_no;
- if ((wr_data[0] == 127) && (pg_no == 0)) {
- aic3262_change_book(aic3262_codec, wr_data[1]);
+ } else {
+ aic_reg.aic326x_register.offset = wr_data[0];
+ aic3262_bulk_write(control, aic_reg.aic326x_register_int,
+ count - 1, &wr_data[1]);
return count;
}
- return i2c_master_send(i2c, wr_data, count);
}
-static long tiload_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
+/**
+ * tiload_ioctl: copy data to user and from user
+ * @filp: pointer to file
+ * @cmd: integer of type command
+ * @arg: argument type
+ *
+ * Return: Return 0 on success
+ */
+static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int num = 0;
void __user *argp = (void __user *)arg;
+
if (_IOC_TYPE(cmd) != aic3262_IOC_MAGIC)
return -ENOTTY;
- dprintk("TiLoad DRIVER : %s\n", __FUNCTION__);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
switch (cmd) {
case aic3262_IOMAGICNUM_GET:
num = copy_to_user(argp, &magic_num, sizeof(int));
@@ -257,7 +268,7 @@ static long tiload_ioctl(struct file *filp,
return num;
}
-/*********** File operations structure for aic3262-tiload programming *************/
+/******* File operations structure for aic3262-tiload programming *********/
static struct file_operations aic3262_fops = {
.owner = THIS_MODULE,
.open = tiload_open,
@@ -267,46 +278,48 @@ static struct file_operations aic3262_fops = {
.unlocked_ioctl = tiload_ioctl,
};
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_driver_init
+/**
+ * aic3262_driver_init: Register a char driver for dynamic aic3262-tiload programming
+ * @codec: pointer variable to codec having codec information
*
- * Purpose : Register a char driver for dynamic aic3262-tiload programming
- *----------------------------------------------------------------------------
+ * Return: Return 0 on seccess
*/
int aic3262_driver_init(struct snd_soc_codec *codec)
{
int result;
dev_t dev = MKDEV(aic3262_major, 0);
- printk("TiLoad DRIVER : %s\n", __FUNCTION__);
+ dprintk("TiLoad DRIVER : %s\n", __func__);
aic3262_codec = codec;
- printk("allocating dynamic major number\n");
+ dprintk("allocating dynamic major number\n");
result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);
if (result < 0) {
- printk("cannot allocate major number %d\n", aic3262_major);
+ dprintk("cannot allocate major number %d\n", aic3262_major);
return result;
}
+
tiload_class = class_create(THIS_MODULE, DEVICE_NAME);
aic3262_major = MAJOR(dev);
- printk("allocated Major Number: %d\n", aic3262_major);
+ dprintk("allocated Major Number: %d\n", aic3262_major);
aic3262_cdev = cdev_alloc();
cdev_init(aic3262_cdev, &aic3262_fops);
aic3262_cdev->owner = THIS_MODULE;
aic3262_cdev->ops = &aic3262_fops;
+ aic_reg.aic326x_register.page = 0;
+ aic_reg.aic326x_register.book = 0;
+
if (cdev_add(aic3262_cdev, dev, 1) < 0) {
- dprintk("aic3262_driver: cdev_add failed \n");
+ dprintk("aic3262_driver: cdev_add failed\n");
unregister_chrdev_region(dev, 1);
aic3262_cdev = NULL;
return 1;
}
- printk("Registered aic3262 TiLoad driver, Major number: %d \n",
- aic3262_major);
- //class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0);
+ dprintk("Registered aic3262 TiLoad driver, Major number: %d\n",
+ aic3262_major);
return 0;
}
diff --git a/sound/soc/codecs/aic326x_tiload.h b/sound/soc/codecs/aic326x_tiload.h
index 6621a4127b16..c11d8a2d06f7 100644
--- a/sound/soc/codecs/aic326x_tiload.h
+++ b/sound/soc/codecs/aic326x_tiload.h
@@ -2,7 +2,7 @@
* linux/sound/soc/codecs/aic3262_tiload.h
*
*
- * Copyright (C) 2012 Texas Instruments, Inc.
+ * Copyright (C) 2011 Texas Instruments Inc.
*
*
*
@@ -24,9 +24,6 @@
#ifndef _AIC3262_TILOAD_H
#define _AIC3262_TILOAD_H
-/* typedefs required for the included header files */
-typedef char *string;
-
/* defines */
#define DEVICE_NAME "tiload_node"
#define aic3262_IOC_MAGIC 0xE0
diff --git a/sound/soc/codecs/aic3xxx_cfw.h b/sound/soc/codecs/aic3xxx_cfw.h
new file mode 100644
index 000000000000..12bc85575195
--- /dev/null
+++ b/sound/soc/codecs/aic3xxx_cfw.h
@@ -0,0 +1,427 @@
+/**
+ * \file Codec Firmware Declarations
+ */
+
+#ifndef CFW_FIRMWARE_H_
+#define CFW_FIRMWARE_H_
+/** \defgroup bt Basic Types */
+/* @{ */
+#ifndef AIC3XXX_CFW_HOST_BLD
+#include <asm-generic/int-ll64.h>
+#else
+typedef unsigned char u8;
+typedef unsigned short int u16;
+typedef unsigned long int u32;
+#endif
+
+#define CFW_FW_MAGIC 0xC0D1F1ED
+
+/** defgroup pd Arbitrary Limitations */
+
+#ifndef CFW_MAX_ID
+#define CFW_MAX_ID (64) /* Max length of string identifies */
+#endif
+
+#ifndef CFW_MAX_DESC
+#define CFW_MAX_DESC (512) /* Max length of description */
+#endif
+/* <Max number of overlays per PFW */
+#ifndef CFW_MAX_NOVLY
+#define CFW_MAX_NOVLY (4)
+#endif
+
+#ifndef CFW_MAX_NCFG
+#define CFW_MAX_NCFG (16) /* Max number of configurations per PFW */
+#endif
+
+#ifndef CFW_MAX_TRANSITIONS
+#define CFW_MAX_TRANSITIONS (32) /* max number of pre-defined transition */
+#endif
+
+#ifndef CFW_MAX_NPFW
+#define CFW_MAX_NPFW (16) /* Max number fo process flows */
+#endif
+
+#ifndef CFW_MAX_MODES
+#define CFW_MAX_MODES (32) /* Max number of modes */
+#endif
+
+#ifndef CFW_MAX_ASI
+#define CFW_MAX_ASI (4) /* Max number ASIs in a single device */
+#endif
+
+
+#ifndef CFW_MAX_CTRL
+#define CFW_MAX_CTRL (16) /* Max number of control per pfw */
+#endif
+
+/** defgroup st Enums, Flags, Macros and Supporting Types */
+
+/**
+ * Sample rate bitmask
+ *
+ */
+enum cfw_fs {
+ CFW_FS_8KHZ = 0x0001u,
+ CFW_FS_11KHZ = 0x0002u,
+ CFW_FS_16KHZ = 0x0004u,
+ CFW_FS_22KHZ = 0x0008u,
+ CFW_FS_24KHZ = 0x0010u,
+ CFW_FS_32KHZ = 0x0020u,
+ CFW_FS_44KHZ = 0x0040u,
+ CFW_FS_48KHZ = 0x0080u,
+ CFW_FS_88KHZ = 0x0100u,
+ CFW_FS_96KHZ = 0x0200u,
+ CFW_FS_176KHZ = 0x0400u,
+ CFW_FS_192KHZ = 0x0800u,
+ CFW_FS_ANY = 0x8000u,
+ CFW_FS_ALL = 0x0FFFu,
+};
+
+/**
+ * Sample rate index
+ *
+ */
+enum cfw_fsi {
+ CFW_FSI_8KHZ,
+ CFW_FSI_11KHZ,
+ CFW_FSI_16KHZ,
+ CFW_FSI_22KHZ,
+ CFW_FSI_24KHZ,
+ CFW_FSI_32KHZ,
+ CFW_FSI_44KHZ,
+ CFW_FSI_48KHZ,
+ CFW_FSI_88KHZ,
+ CFW_FSI_96KHZ,
+ CFW_FSI_176KHZ,
+ CFW_FSI_192KHZ,
+ CFW_FSI_ANY = 15,
+};
+
+/**
+ * Device Family Identifier
+ *
+ */
+enum __attribute__ ((__packed__)) cfw_dfamily {
+ CFW_DFM_TYPE_A,
+ CFW_DFM_TYPE_B,
+ CFW_DFM_TYPE_C
+};
+
+/**
+ * Device Identifier
+ *
+ */
+enum __attribute__ ((__packed__)) cfw_device {
+ CFW_DEV_DAC3120,
+ CFW_DEV_DAC3100,
+
+ CFW_DEV_AIC3120,
+ CFW_DEV_AIC3100,
+ CFW_DEV_AIC3110,
+ CFW_DEV_AIC3111,
+
+ CFW_DEV_AIC36,
+
+ CFW_DEV_AIC3206,
+ CFW_DEV_AIC3204,
+ CFW_DEV_AIC3254,
+ CFW_DEV_AIC3256,
+ CFW_DEV_AIC3253,
+
+ CFW_DEV_AIC3212,
+ CFW_DEV_AIC3262,
+ CFW_DEV_AIC3017,
+ CFW_DEV_AIC3008,
+
+};
+
+/**
+ * Transition Sequence Identifier
+ *
+ */
+enum cfw_transition_t {
+ CFW_TRN_INIT,
+ CFW_TRN_RESUME,
+ CFW_TRN_NEUTRAL,
+ CFW_TRN_A_MUTE,
+ CFW_TRN_D_MUTE,
+ CFW_TRN_AD_MUTE,
+ CFW_TRN_A_UNMUTE,
+ CFW_TRN_D_UNMUTE,
+ CFW_TRN_AD_UNMUTE,
+ CFW_TRN_SUSPEND,
+ CFW_TRN_EXIT,
+ CFW_TRN_N
+};
+
+static const char * const cfw_transition_id[] = {
+ [CFW_TRN_INIT] "INIT",
+ [CFW_TRN_RESUME] "RESUME",
+ [CFW_TRN_NEUTRAL] "NEUTRAL",
+ [CFW_TRN_A_MUTE] "A_MUTE",
+ [CFW_TRN_D_MUTE] "D_MUTE",
+ [CFW_TRN_AD_MUTE] "AD_MUTE",
+ [CFW_TRN_A_UNMUTE] "A_UNMUTE",
+ [CFW_TRN_D_UNMUTE] "D_UNMUTE",
+ [CFW_TRN_AD_UNMUTE] "AD_UNMUTE",
+ [CFW_TRN_SUSPEND] "SUSPEND",
+ [CFW_TRN_EXIT] "EXIT",
+};
+
+/** defgroup ds Data Structures */
+
+/**
+* CFW Meta Command
+* These commands do not appear in the register
+* set of the device.
+* Mainly delay, wait and set_bits.
+*/
+enum __attribute__ ((__packed__)) cfw_meta_cmd {
+ CFW_META_DELAY = 0x80,
+ CFW_META_UPDTBITS,
+ CFW_META_WAITBITS,
+ CFW_META_LOCK,
+};
+
+/**
+* CFW Delay
+* Used for the meta command delay
+* Has one parameter of delay time in ms
+*/
+struct cfw_meta_delay {
+ u16 delay;
+ enum cfw_meta_cmd mcmd;
+ u8 unused1;
+};
+
+/**
+* CFW set_bits or wait
+* Both these meta commands have same arguments
+* mcmd will be used to specify which command it is
+* has parameters of book, page, offset and mask
+*/
+struct cfw_meta_bitop {
+ u16 unused1;
+ enum cfw_meta_cmd mcmd;
+ u8 mask;
+};
+
+/**
+* CFW meta register
+* Contains the data structures for the meta commands
+*/
+union cfw_meta_register {
+ struct {
+ u16 unused1;
+ enum cfw_meta_cmd mcmd;
+ u8 unused2;
+ };
+ struct cfw_meta_delay delay;
+ struct cfw_meta_bitop bitop;
+};
+
+/**
+ * CFW Register
+ *
+ * A single reg write
+ *
+ */
+union cfw_register {
+ struct {
+ u8 book;
+ u8 page;
+ u8 offset;
+ u8 data;
+ };
+ u32 bpod;
+ union cfw_meta_register meta;
+};
+
+/**
+ * CFW Burst
+ *
+ * A single I2C/SPI burst write sequence
+ *
+ */
+struct cfw_burst {
+ u32 length;
+ union {
+ union cfw_register reg;
+ struct {
+ u8 bpo[3];
+ u8 data[1];
+ };
+ };
+};
+
+/**
+ * CFW Command
+ *
+ * Can be a either a
+ * -# single register write,
+ * -# a burst write, or
+ * -# meta-command
+ *
+ */
+union cfw_cmd {
+ union cfw_register reg;
+ struct cfw_burst *burst;
+};
+
+/**
+ * CFW Block Type
+ *
+ * Block identifier
+ *
+ */
+enum __attribute__ ((__packed__)) cfw_block_t {
+ CFW_BLOCK_SYSTEM_PRE,
+ CFW_BLOCK_A_INST,
+ CFW_BLOCK_A_A_COEF,
+ CFW_BLOCK_A_B_COEF,
+ CFW_BLOCK_A_F_COEF,
+ CFW_BLOCK_D_INST,
+ CFW_BLOCK_D_A1_COEF,
+ CFW_BLOCK_D_B1_COEF,
+ CFW_BLOCK_D_A2_COEF,
+ CFW_BLOCK_D_B2_COEF,
+ CFW_BLOCK_D_F_COEF,
+ CFW_BLOCK_SYSTEM_POST,
+ CFW_BLOCK_N,
+ CFW_BLOCK_INVALID,
+ CFW_BLOCK_BURSTS = 0x80
+};
+#define CFW_BLOCK_BURSTS(x) ((x)&CFW_BLOCK_BURSTS)
+#define CFW_BLOCK_TYPE(x) ((x)&(~CFW_BLOCK_BURSTS))
+#define CFW_BLOCK_D_A_COEF CFW_BLOCK_D_A1_COEF
+#define CFW_BLOCK_D_B_COEF CFW_BLOCK_D_B1_COEF
+
+/**
+ * CFW Block
+ *
+ * A block of logically grouped sequences/commands/meta-commands
+ *
+ */
+struct cfw_block {
+ enum cfw_block_t type;
+ int ncmds;
+ union cfw_cmd cmd[];
+};
+
+/**
+ * CFW Image
+ *
+ * A downloadable image
+ */
+struct cfw_image {
+ char name[CFW_MAX_ID]; /* Name of the pfw/overlay/configuration */
+ char desc[CFW_MAX_DESC]; /* User string */
+ int mute_flags;
+ struct cfw_block *block[CFW_BLOCK_N];
+};
+
+struct cfw_control {
+ char name[CFW_MAX_ID]; /* Control identifier */
+ char desc[CFW_MAX_DESC];/* User string */
+ int mute_flags;
+
+ int min; /* Min value of control (*100) */
+ int max; /* Max value of control (*100) */
+ int step; /* Control step size (*100) */
+
+ int imax; /* Max index into controls array */
+ int ireset; /* Reset control to defaults */
+ int icur; /* Last value set */
+ struct cfw_block **output; /* Array of sequences to send */
+};
+
+/**
+ * Process flow
+ *
+ * Complete description of a process flow
+ */
+struct cfw_pfw {
+ char name[CFW_MAX_ID]; /* Name of the process flow */
+ char desc[CFW_MAX_DESC]; /* User string */
+ u32 version;
+ u8 prb_a;
+ u8 prb_d;
+ int novly; /* Number of overlays (1 or more) */
+ int ncfg; /* Number of configurations (0 or more) */
+ int nctrl; /* Number of run-time controls */
+ struct cfw_block *pll;
+ struct cfw_image *base; /* Base sequence */
+ /* Overlay and cfg */
+ struct cfw_image *ovly_cfg[CFW_MAX_NOVLY][CFW_MAX_NCFG];
+ /* Array of run-time controls */
+ struct cfw_control *ctrl[CFW_MAX_CTRL];
+};
+
+/**
+ * Process transition
+ *
+ * Sequence for specific state transisitions within the driver
+ *
+ */
+struct cfw_transition {
+ char name[CFW_MAX_ID]; /* Name of the transition */
+ char desc[CFW_MAX_DESC]; /* User string */
+ struct cfw_block *block;
+};
+
+/**
+ * Device audio mode
+ *
+ * Structure linking various operating modes to process flows,
+ * configurations and sequences
+ *
+ */
+struct cfw_mode {
+ char name[CFW_MAX_ID];
+ char desc[CFW_MAX_DESC]; /* User string */
+ u32 flags;
+ u8 pfw;
+ u8 ovly;
+ u8 cfg;
+ struct cfw_block *entry;
+ struct cfw_block *exit;
+};
+
+struct cfw_asoc_toc_entry {
+ char etext[CFW_MAX_ID];
+ int mode;
+ int cfg;
+};
+
+struct cfw_asoc_toc {
+ int nentries;
+ struct cfw_asoc_toc_entry entry[];
+};
+
+/**
+ * CFW Project
+ *
+ * Top level structure describing the CFW project
+ */
+struct cfw_project {
+ u32 magic;
+ u32 bmagic;
+ u32 size;
+ u32 cksum;
+ u32 version;
+ u32 tstamp;
+ char name[CFW_MAX_ID]; /* Project name */
+ char desc[CFW_MAX_DESC]; /* User string */
+ enum cfw_dfamily dfamily;
+ enum cfw_device device;
+ u32 flags;
+ struct cfw_transition *transition[CFW_MAX_TRANSITIONS];
+ u16 npfw; /* Number of process flows */
+ u16 nmode; /* Number of operating modes */
+ struct cfw_pfw *pfw[CFW_MAX_NPFW]; /* Indices to PFW locations */
+ struct cfw_mode *mode[CFW_MAX_MODES];
+ struct cfw_asoc_toc *asoc_toc;
+};
+
+#endif /* CFW_FIRMWARE_H_ */
diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.c b/sound/soc/codecs/aic3xxx_cfw_ops.c
new file mode 100644
index 000000000000..83bcdf1d69bc
--- /dev/null
+++ b/sound/soc/codecs/aic3xxx_cfw_ops.c
@@ -0,0 +1,922 @@
+#ifndef AIC3XXX_CFW_HOST_BLD
+# include <linux/module.h>
+# include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <linux/slab.h>
+#include <sound/tlv.h>
+# define warn(fmt, ...) printk(fmt "\n", ##__VA_ARGS__)
+# define error(fmt, ...) printk(fmt "\n", ##__VA_ARGS__)
+
+#else
+# define _GNU_SOURCE
+# include <stdlib.h>
+# include "utils.h"
+# include <string.h>
+# include <assert.h>
+# define EINVAL 1
+
+#endif
+
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+#ifndef AIC3XXX_CFW_HOST_BLD
+static struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n);
+#endif
+
+
+/*
+ * Firmware version numbers are used to make sure that the
+ * host and target code stay in sync. It is _not_ recommended
+ * to provide this number from the outside (E.g., from a makefile)
+ * Instead, a set of automated tools are relied upon to keep the numbers
+ * in sync at the time of host testing.
+ */
+#define CFW_FW_VERSION 0x000100B3
+
+static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim);
+static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim);
+static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb,
+ u32 mute_flags);
+static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb);
+static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask,
+ u8 data);
+static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps);
+static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags);
+static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg);
+static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg);
+static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype);
+static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi);
+static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param);
+
+
+#if defined(AIC3XXX_CFW_HOST_BLD)
+
+static int mutex_init(struct mutex *m)
+{
+ m->lock = 0;
+ return 0;
+}
+
+static int mutex_lock(struct mutex *m)
+{
+ assert(m->lock == 0);
+ m->lock = 1;
+ return 0;
+}
+
+static int mutex_unlock(struct mutex *m)
+{
+ assert(m->lock == 1);
+ m->lock = 0;
+ return 0;
+}
+/*
+static void mdelay(int val)
+{
+ int i;
+ for (i = 0; i < (val * 10); i++);
+}
+*/
+#endif
+
+int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops,
+ void *ops_obj)
+{
+ ps->ops = ops;
+ ps->ops_obj = ops_obj;
+ ps->pjt = NULL;
+ mutex_init(&ps->mutex);
+ return 0;
+}
+
+int aic3xxx_cfw_lock(struct cfw_state *ps, int lock)
+{
+ if (lock)
+ mutex_lock(&ps->mutex);
+ else
+ mutex_unlock(&ps->mutex);
+ return 0;
+}
+
+int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n)
+{
+ ps->pjt = aic3xxx_cfw_unpickle(pcfw, n);
+ ps->cur_mode_id =
+ ps->cur_mode = ps->cur_pfw = ps->cur_ovly = ps->cur_cfg = -1;
+ if (ps->pjt == NULL)
+ return -1;
+ return 0;
+}
+
+int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode)
+{
+ struct cfw_project *pjt;
+ int ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ pjt = ps->pjt;
+ if (pjt == NULL) {
+ aic3xxx_cfw_lock(ps, 0);
+ return -1;
+ }
+ ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, pjt->mode[mode]->cfg);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+
+int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg)
+{
+ int ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ ret = aic3xxx_cfw_setcfg_u(ps, cfg);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+
+static int aic3xxx_cfw_setcfg_u(struct cfw_state *ps, int cfg)
+{
+ struct cfw_project *pjt = ps->pjt;
+ struct cfw_pfw *pfw;
+
+ if (pjt == NULL)
+ return -1;
+ if (ps->cur_pfw < 0 || ps->cur_pfw >= pjt->npfw)
+ return -1;
+ if (ps->cur_cfg == cfg)
+ return 0;
+ pfw = pjt->pfw[ps->cur_pfw];
+ if (pfw->ncfg == 0 && cfg != 0)
+ return -1;
+ if (cfg > 0 && cfg >= pfw->ncfg)
+ return -1;
+ ps->cur_cfg = cfg;
+ aic3xxx_cfw_set_mode_id(ps);
+ if (pfw->ncfg != 0)
+ return aic3xxx_cfw_dlcfg(ps,
+ pfw->ovly_cfg[ps->cur_ovly][ps->
+ cur_cfg]);
+ return 0;
+}
+
+int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg)
+{
+ int ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ ret = aic3xxx_cfw_setmode_cfg_u(ps, mode, cfg);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+
+static int aic3xxx_cfw_setmode_cfg_u(struct cfw_state *ps, int mode, int cfg)
+{
+ struct cfw_project *pjt = ps->pjt;
+ int which = 0;
+ struct cfw_pfw *pfw;
+ struct cfw_image *im;
+
+ if (pjt == NULL)
+ return -1;
+ if ((mode < 0) || (mode >= pjt->nmode))
+ return -1;
+ if (cfg < 0)
+ return -1;
+ if (mode == ps->cur_mode)
+ return aic3xxx_cfw_setcfg_u(ps, cfg);
+
+ /* Apply exit sequence for previous mode if present */
+ if (ps->cur_mode >= 0 && pjt->mode[ps->cur_mode]->exit)
+ aic3xxx_cfw_dlcmds(ps, pjt->mode[ps->cur_mode]->exit);
+
+ if (pjt->mode[mode]->pfw < pjt->npfw) {
+ /* New mode uses miniDSP */
+ pfw = pjt->pfw[pjt->mode[mode]->pfw];
+ /* Make sure cfg is valid and supported in this mode */
+ if (pfw->ncfg == 0 && cfg != 0)
+ return -1;
+ if (cfg > 0 && cfg >= pfw->ncfg)
+ return -1;
+ /*
+ * Decisions about which miniDSP to stop/restart are taken
+ * on the basis of sections present in the _base_ image
+ * This allows for correct sync mode operation even in cases
+ * where the base PFW uses both miniDSPs where a particular
+ * overlay applies only to one
+ */
+ im = pfw->base;
+ if (im->block[CFW_BLOCK_A_INST])
+ which |= AIC3XX_COPS_MDSP_A;
+ if (im->block[CFW_BLOCK_D_INST])
+ which |= AIC3XX_COPS_MDSP_D;
+
+ /* New mode requires different PFW */
+ if (pjt->mode[mode]->pfw != ps->cur_pfw) {
+ ps->cur_pfw = pjt->mode[mode]->pfw;
+ ps->cur_ovly = 0;
+ ps->cur_cfg = 0;
+
+ which = ps->ops->stop(ps->ops_obj, which);
+ aic3xxx_cfw_dlimage(ps, im);
+ if (pjt->mode[mode]->ovly
+ && pjt->mode[mode]->ovly < pfw->novly) {
+ /* New mode uses ovly */
+ if (pfw->ovly_cfg[pjt->mode[mode]
+ ->ovly][cfg] != NULL)
+ aic3xxx_cfw_dlimage(ps,
+ pfw->ovly_cfg[pjt->
+ mode[mode]->
+ ovly][cfg]);
+ } else if (pfw->ncfg > 0) {
+ /* new mode needs only a cfg change */
+ aic3xxx_cfw_dlimage(ps, pfw->ovly_cfg[0][cfg]);
+ }
+ ps->ops->restore(ps->ops_obj, which);
+
+ } else if (pjt->mode[mode]->ovly != ps->cur_ovly) {
+ /* New mode requires only an ovly change */
+ which = ps->ops->stop(ps->ops_obj, which);
+ aic3xxx_cfw_dlimage(ps,
+ pfw->ovly_cfg[pjt->mode[mode]->
+ ovly][cfg]);
+ ps->ops->restore(ps->ops_obj, which);
+ } else if (pfw->ncfg > 0 && cfg != ps->cur_cfg) {
+ /* New mode requires only a cfg change */
+ aic3xxx_cfw_dlcfg(ps,
+ pfw->ovly_cfg[pjt->mode[mode]->
+ ovly][cfg]);
+ }
+ ps->cur_ovly = pjt->mode[mode]->ovly;
+ ps->cur_cfg = cfg;
+
+ ps->cur_mode = mode;
+ aic3xxx_cfw_set_pll_u(ps, 0);
+
+ } else if (pjt->mode[mode]->pfw != 0xFF) {
+ warn("Bad pfw setting detected (%d). Max pfw=%d",
+ pjt->mode[mode]->pfw, pjt->npfw);
+ }
+ ps->cur_mode = mode;
+ aic3xxx_cfw_set_mode_id(ps);
+ /* Transition to netural mode */
+ aic3xxx_cfw_transition_u(ps, "NEUTRAL");
+ /* Apply entry sequence if present */
+ if (pjt->mode[mode]->entry)
+ aic3xxx_cfw_dlcmds(ps, pjt->mode[mode]->entry);
+ DBG("setmode_cfg: DONE (mode=%d pfw=%d ovly=%d cfg=%d)", ps->cur_mode,
+ ps->cur_pfw, ps->cur_ovly, ps->cur_cfg);
+ return 0;
+}
+
+int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype)
+{
+ int ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ ret = aic3xxx_cfw_transition_u(ps, ttype);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+
+static int aic3xxx_cfw_transition_u(struct cfw_state *ps, char *ttype)
+{
+ int i;
+
+ if (ps->pjt == NULL)
+ return -1;
+ for (i = 0; i < CFW_TRN_N; ++i) {
+ if (!strcasecmp(ttype, cfw_transition_id[i])) {
+ DBG("Sending transition %s[%d]", ttype, i);
+ if (ps->pjt->transition[i]) {
+ aic3xxx_cfw_dlcmds(ps,
+ ps->pjt->transition[i]->
+ block);
+ }
+ return 0;
+ }
+ }
+ warn("Transition %s not present or invalid", ttype);
+ return 0;
+}
+
+int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi)
+{
+ int ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ ret = aic3xxx_cfw_set_pll_u(ps, asi);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+
+static int aic3xxx_cfw_set_pll_u(struct cfw_state *ps, int asi)
+{
+ struct cfw_project *pjt = ps->pjt;
+ struct cfw_pfw *pfw;
+
+ if (pjt == NULL)
+ return -1;
+ if (ps->cur_mode < 0)
+ return -EINVAL;
+ pfw = pjt->pfw[pjt->mode[ps->cur_mode]->pfw];
+ if (pfw->pll) {
+ DBG("Configuring PLL for ASI%d using PFW%d", asi,
+ pjt->mode[ps->cur_mode]->pfw);
+ aic3xxx_cfw_dlcmds(ps, pfw->pll);
+ }
+ return 0;
+}
+
+int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param)
+{
+ int ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ ret = aic3xxx_cfw_control_u(ps, cname, param);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+
+static int aic3xxx_cfw_control_u(struct cfw_state *ps, char *cname, int param)
+{
+ struct cfw_pfw *pfw;
+ int i;
+
+ if (ps->cur_pfw < 0 || ps->cur_pfw >= ps->pjt->npfw) {
+ warn("Not in MiniDSP mode");
+ return 0;
+ }
+ pfw = ps->pjt->pfw[ps->cur_pfw];
+ for (i = 0; i < pfw->nctrl; ++i) {
+ if (!strcasecmp(cname, pfw->ctrl[i]->name)) {
+ struct cfw_control *pc = pfw->ctrl[i];
+ if (param < 0 || param > pc->imax) {
+ warn("Parameter out of range\n");
+ return -EINVAL;
+ }
+ DBG("Sending control %s[%d]", cname, param);
+ pc->icur = param;
+ aic3xxx_cfw_dlctl(ps, pc->output[param],
+ pc->mute_flags);
+ return 0;
+ }
+ }
+ warn("Control named %s nort found in pfw %s", cname, pfw->name);
+
+ return 0;
+}
+
+static void aic3xxx_cfw_dlcmds(struct cfw_state *ps, struct cfw_block *pb)
+{
+ int i = 0, lock = 0;
+
+ while (i < pb->ncmds) {
+ if (CFW_BLOCK_BURSTS(pb->type))
+ ps->ops->bulk_write(ps->ops_obj,
+ pb->cmd[i].burst->reg.bpod,
+ pb->cmd[i].burst->length,
+ pb->cmd[i].burst->data);
+ else {
+ struct cfw_meta_delay d = pb->cmd[i].reg.meta.delay;
+ struct cfw_meta_bitop b = pb->cmd[i].reg.meta.bitop;
+ switch (pb->cmd[i].reg.meta.mcmd) {
+ case CFW_META_DELAY:
+ mdelay(d.delay);
+ break;
+ case CFW_META_UPDTBITS:
+ ps->ops->set_bits(ps->ops_obj,
+ pb->cmd[i + 1].reg.bpod,
+ b.mask,
+ pb->cmd[i + 1].reg.data);
+ i++;
+ break;
+ case CFW_META_WAITBITS:
+ aic3xxx_wait(ps, pb->cmd[i + 1].reg.bpod,
+ b.mask, pb->cmd[i + 1].reg.data);
+ i++;
+ break;
+ case CFW_META_LOCK:
+ if (d.delay) {
+ ps->ops->lock(ps->ops_obj);
+ lock = 1;
+ } else {
+ if (!lock)
+ error("already lock\n");
+ ps->ops->unlock(ps->ops_obj);
+ lock = 0;
+ }
+ break;
+ default:
+ ps->ops->reg_write(ps->ops_obj,
+ pb->cmd[i].reg.bpod,
+ pb->cmd[i].reg.data);
+ }
+ }
+ ++i;
+ }
+ if (lock)
+ error("exiting blkcmds with lock ON");
+}
+
+static void aic3xxx_wait(struct cfw_state *ps, unsigned int reg, u8 mask,
+ u8 data)
+{
+ while ((ps->ops->reg_read(ps->ops_obj, reg) & mask) != data)
+ mdelay(2);
+}
+
+static const struct {
+ u32 mdsp;
+ int buf_a, buf_b;
+ u32 swap;
+} csecs[] = {
+ {
+ .mdsp = AIC3XX_COPS_MDSP_A,
+ .swap = AIC3XX_ABUF_MDSP_A,
+ .buf_a = CFW_BLOCK_A_A_COEF,
+ .buf_b = CFW_BLOCK_A_B_COEF
+ },
+ {
+ .mdsp = AIC3XX_COPS_MDSP_D,
+ .swap = AIC3XX_ABUF_MDSP_D1,
+ .buf_a = CFW_BLOCK_D_A1_COEF,
+ .buf_b = CFW_BLOCK_D_B1_COEF
+ },
+ {
+ .mdsp = AIC3XX_COPS_MDSP_D,
+ .swap = AIC3XX_ABUF_MDSP_D2,
+ .buf_a = CFW_BLOCK_D_A2_COEF,
+ .buf_b = CFW_BLOCK_D_B2_COEF
+ },
+};
+
+static int aic3xxx_cfw_dlctl(struct cfw_state *ps, struct cfw_block *pb,
+ u32 mute_flags)
+{
+ int i, btype = CFW_BLOCK_TYPE(pb->type);
+ int run_state = ps->ops->lock(ps->ops_obj);
+
+ DBG("Download CTL");
+ for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) {
+ if (csecs[i].buf_a == btype || csecs[i].buf_b == btype) {
+ DBG("\tDownload once to %d", btype);
+ aic3xxx_cfw_dlcmds(ps, pb);
+ if (run_state & csecs[i].mdsp) {
+ DBG("Download again %d", btype);
+ aic3xxx_cfw_mute(ps, 1, run_state & mute_flags);
+ ps->ops->bswap(ps->ops_obj, csecs[i].swap);
+ aic3xxx_cfw_mute(ps, 0, run_state & mute_flags);
+ aic3xxx_cfw_dlcmds(ps, pb);
+ }
+ break;
+ }
+ }
+ ps->ops->unlock(ps->ops_obj);
+ return 0;
+}
+
+static int aic3xxx_cfw_dlcfg(struct cfw_state *ps, struct cfw_image *pim)
+{
+ int i, run_state, swap;
+
+ DBG("Download CFG %s", pim->name);
+ run_state = ps->ops->lock(ps->ops_obj);
+ swap = 0;
+ for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) {
+ if (pim->block[csecs[i].buf_a]) {
+ if (run_state & csecs[i].mdsp) {
+ aic3xxx_cfw_dlcmds(ps,
+ pim->block[csecs[i].buf_a]);
+ swap |= csecs[i].swap;
+ } else {
+ aic3xxx_cfw_dlcmds(ps,
+ pim->block[csecs[i].buf_a]);
+ aic3xxx_cfw_dlcmds(ps,
+ pim->block[csecs[i].buf_b]);
+ }
+ }
+ }
+ if (swap) {
+ aic3xxx_cfw_mute(ps, 1, run_state & pim->mute_flags);
+ ps->ops->bswap(ps->ops_obj, swap);
+ aic3xxx_cfw_mute(ps, 0, run_state & pim->mute_flags);
+ for (i = 0; i < sizeof(csecs) / sizeof(csecs[0]); ++i) {
+ if (pim->block[csecs[i].buf_a]) {
+ if (run_state & csecs[i].mdsp)
+ aic3xxx_cfw_dlcmds(ps,
+ pim->block[csecs[i].
+ buf_a]);
+ }
+ }
+ }
+ ps->ops->unlock(ps->ops_obj);
+ return 0;
+}
+
+static int aic3xxx_cfw_dlimage(struct cfw_state *ps, struct cfw_image *pim)
+{
+ int i;
+
+ DBG("Download IMAGE %s", pim->name);
+ for (i = 0; i < CFW_BLOCK_N; ++i)
+ if (pim->block[i])
+ aic3xxx_cfw_dlcmds(ps, pim->block[i]);
+ return 0;
+}
+
+static int aic3xxx_cfw_mute(struct cfw_state *ps, int mute, u32 flags)
+{
+ if ((flags & AIC3XX_COPS_MDSP_D) && (flags & AIC3XX_COPS_MDSP_A))
+ aic3xxx_cfw_transition_u(ps, mute ? "AD_MUTE" : "AD_UNMUTE");
+ else if (flags & AIC3XX_COPS_MDSP_D)
+ aic3xxx_cfw_transition_u(ps, mute ? "D_MUTE" : "D_UNMUTE");
+ else if (flags & AIC3XX_COPS_MDSP_A)
+ aic3xxx_cfw_transition_u(ps, mute ? "A_MUTE" : "A_UNMUTE");
+ return 0;
+}
+
+#define FW_NDX2PTR(x, b) do { \
+x = (void *)((u8 *)(b) + ((int)(x))); \
+} while (0)
+
+static void aic3xxx_cfw_unpickle_block(struct cfw_block *pb, void *p)
+{
+ int i;
+
+ if (CFW_BLOCK_BURSTS(pb->type))
+ for (i = 0; i < pb->ncmds; ++i)
+ FW_NDX2PTR(pb->cmd[i].burst, p);
+}
+
+static void aic3xxx_cfw_unpickle_image(struct cfw_image *im, void *p)
+{
+ int i;
+ for (i = 0; i < CFW_BLOCK_N; ++i)
+ if (im->block[i]) {
+ FW_NDX2PTR(im->block[i], p);
+ aic3xxx_cfw_unpickle_block(im->block[i], p);
+ }
+}
+
+static void aic3xxx_cfw_unpickle_control(struct cfw_control *ct, void *p)
+{
+ int i;
+ FW_NDX2PTR(ct->output, p);
+ for (i = 0; i <= ct->imax; ++i) {
+ FW_NDX2PTR(ct->output[i], p);
+ aic3xxx_cfw_unpickle_block(ct->output[i], p);
+ }
+}
+#ifndef AIC3XXX_CFW_HOST_BLD
+static
+#endif
+unsigned int crc32(unsigned int *pdata, int n)
+{
+ u32 crc = 0, i, crc_poly = 0x04C11DB7; /* CRC - 32 */
+ u32 msb;
+ u32 residue_value;
+ int bits;
+
+ for (i = 0; i < (n >> 2); i++) {
+ bits = 32;
+ while (--bits >= 0) {
+ msb = crc & 0x80000000;
+ crc = (crc << 1) ^ ((*pdata >> bits) & 1);
+ if (msb)
+ crc = crc ^ crc_poly;
+ }
+ pdata++;
+ }
+
+ switch (n & 3) {
+ case 0:
+ break;
+ case 1:
+ residue_value = (*pdata & 0xFF);
+ bits = 8;
+ break;
+ case 2:
+ residue_value = (*pdata & 0xFFFF);
+ bits = 16;
+ break;
+ case 3:
+ residue_value = (*pdata & 0xFFFFFF);
+ bits = 24;
+ break;
+ }
+
+ if (n & 3) {
+ while (--bits >= 0) {
+ msb = crc & 0x80000000;
+ crc = (crc << 1) ^ ((residue_value >> bits) & 1);
+ if (msb)
+ crc = crc ^ crc_poly;
+ }
+ }
+ return crc;
+}
+
+static int crc_chk(void *p, int n)
+{
+ struct cfw_project *pjt = (void *)p;
+ u32 crc = pjt->cksum, crc_comp;
+
+ pjt->cksum = 0;
+ DBG("Entering crc %d", n);
+ crc_comp = crc32(p, n);
+ if (crc_comp != crc) {
+ DBG("CRC mismatch 0x%08X != 0x%08X", crc, crc_comp);
+ return 0;
+ }
+ DBG("CRC pass");
+ pjt->cksum = crc;
+ return 1;
+}
+#ifndef AIC3XXX_CFW_HOST_BLD
+static
+#endif
+struct cfw_project *aic3xxx_cfw_unpickle(void *p, int n)
+{
+ struct cfw_project *pjt = p;
+ int i, j, k;
+
+ if (pjt->magic != CFW_FW_MAGIC ||
+ pjt->size != n || pjt->bmagic != CFW_FW_VERSION ||
+ !crc_chk(p, n)) {
+ error
+ ("magic:0x%08X!=0x%08X || size:%d!=%d ||version:0x%08X!=0x%08X",
+ pjt->magic, CFW_FW_MAGIC, pjt->size, n, pjt->cksum,
+ CFW_FW_VERSION);
+
+ return NULL;
+ }
+ DBG("Loaded firmware inside unpickle\n");
+
+ for (i = 0; i < CFW_MAX_TRANSITIONS; i++) {
+ if (pjt->transition[i]) {
+ FW_NDX2PTR(pjt->transition[i], p);
+ FW_NDX2PTR(pjt->transition[i]->block, p);
+ aic3xxx_cfw_unpickle_block(pjt->transition[i]->block,
+ p);
+ }
+ }
+
+ for (i = 0; i < pjt->npfw; i++) {
+ DBG("loading pfw %d\n", i);
+ FW_NDX2PTR(pjt->pfw[i], p);
+ if (pjt->pfw[i]->base) {
+ FW_NDX2PTR(pjt->pfw[i]->base, p);
+ aic3xxx_cfw_unpickle_image(pjt->pfw[i]->base, p);
+ }
+ if (pjt->pfw[i]->pll) {
+ FW_NDX2PTR(pjt->pfw[i]->pll, p);
+ aic3xxx_cfw_unpickle_block(pjt->pfw[i]->pll, p);
+ }
+ for (j = 0; j < pjt->pfw[i]->novly; ++j)
+ for (k = 0; k < pjt->pfw[i]->ncfg; ++k) {
+ FW_NDX2PTR(pjt->pfw[i]->ovly_cfg[j][k], p);
+ aic3xxx_cfw_unpickle_image(pjt->pfw[i]->
+ ovly_cfg[j][k], p);
+ }
+ for (j = 0; j < pjt->pfw[i]->nctrl; ++j) {
+ FW_NDX2PTR(pjt->pfw[i]->ctrl[j], p);
+ aic3xxx_cfw_unpickle_control(pjt->pfw[i]->ctrl[j], p);
+ }
+ }
+
+ DBG("loaded pfw's\n");
+ for (i = 0; i < pjt->nmode; i++) {
+ FW_NDX2PTR(pjt->mode[i], p);
+ if (pjt->mode[i]->entry) {
+ FW_NDX2PTR(pjt->mode[i]->entry, p);
+ aic3xxx_cfw_unpickle_block(pjt->mode[i]->entry, p);
+ }
+ if (pjt->mode[i]->exit) {
+ FW_NDX2PTR(pjt->mode[i]->exit, p);
+ aic3xxx_cfw_unpickle_block(pjt->mode[i]->exit, p);
+ }
+ }
+ if (pjt->asoc_toc)
+ FW_NDX2PTR(pjt->asoc_toc, p);
+ else {
+ warn("asoc_toc not defined. FW version mismatch?");
+ return NULL;
+ }
+ DBG("loaded modes");
+ return pjt;
+}
+
+#ifndef AIC3XXX_CFW_HOST_BLD
+static int aic3xxx_get_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cfw_state *ps =
+ (struct cfw_state *) kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cfw_pfw *pfw;
+ int i;
+
+ if (ps->cur_pfw >= ps->pjt->npfw) {
+ DBG("Not in MiniDSP mode");
+ return 0;
+ }
+ pfw = ps->pjt->pfw[ps->cur_pfw];
+ for (i = 0; i < pfw->nctrl; ++i) {
+ if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) {
+ struct cfw_control *pc = pfw->ctrl[i];
+ ucontrol->value.integer.value[0] = pc->icur;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static int aic3xxx_put_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct cfw_state *ps =
+ (struct cfw_state *) kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+
+ aic3xxx_cfw_control(ps, kcontrol->id.name,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int aic3xxx_info_control(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *ucontrol)
+{
+ struct cfw_state *ps =
+ (struct cfw_state *) kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct cfw_pfw *pfw;
+ int i;
+
+ if (ps->cur_pfw >= ps->pjt->npfw) {
+ DBG("Not in MiniDSP mode");
+ return 0;
+ }
+ pfw = ps->pjt->pfw[ps->cur_pfw];
+ for (i = 0; i < pfw->nctrl; ++i) {
+ if (!strcasecmp(kcontrol->id.name, pfw->ctrl[i]->name)) {
+ struct cfw_control *pc = pfw->ctrl[i];
+ ucontrol->value.integer.min = 0;
+ ucontrol->value.integer.max = pc->imax;
+ if (pc->imax == 1)
+ ucontrol->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ ucontrol->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ }
+ }
+
+ ucontrol->count = 1;
+ return 0;
+}
+#endif
+int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps)
+{
+ int i, j;
+ struct cfw_pfw *pfw;
+
+ for (j = 0; j < ps->pjt->npfw; ++j) {
+ pfw = ps->pjt->pfw[j];
+
+ for (i = 0; i < pfw->nctrl; ++i) {
+ struct cfw_control *pc = pfw->ctrl[i];
+#ifndef AIC3XXX_CFW_HOST_BLD
+ struct snd_kcontrol_new *generic_control =
+ kzalloc(sizeof(struct snd_kcontrol_new),
+ GFP_KERNEL);
+ unsigned int *tlv_array =
+ kzalloc(4 * sizeof(unsigned int), GFP_KERNEL);
+
+ if (generic_control == NULL)
+ return -ENOMEM;
+ generic_control->access =
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ tlv_array[0] = SNDRV_CTL_TLVT_DB_SCALE;
+ tlv_array[1] = 2 * sizeof(unsigned int);
+ tlv_array[2] = pc->min;
+ tlv_array[3] = ((pc->step) & TLV_DB_SCALE_MASK);
+ if (pc->step > 0)
+ generic_control->tlv.p = tlv_array;
+ generic_control->name = pc->name;
+ generic_control->private_value = (unsigned long) ps;
+ generic_control->get = aic3xxx_get_control;
+ generic_control->put = aic3xxx_put_control;
+ generic_control->info = aic3xxx_info_control;
+ generic_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+#endif
+ DBG("Adding control %s", pc->name);
+#ifndef AIC3XXX_CFW_HOST_BLD
+ snd_soc_add_controls(codec, generic_control, 1);
+#endif
+ }
+ }
+ return 0;
+
+}
+
+static int aic3xxx_cfw_set_mode_id(struct cfw_state *ps)
+{
+ struct cfw_asoc_toc *toc = ps->pjt->asoc_toc;
+ int i;
+
+ for (i = 0; i < toc->nentries; ++i) {
+ if (toc->entry[i].cfg == ps->cur_cfg &&
+ toc->entry[i].mode == ps->cur_mode) {
+ ps->cur_mode_id = i;
+ return 0;
+ }
+ }
+ DBG("Unknown mode, cfg combination [%d, %d]",
+ ps->cur_mode, ps->cur_cfg);
+ return -1;
+}
+#ifndef AIC3XXX_CFW_HOST_BLD
+static int aic3xxx_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct cfw_state *ps = (struct cfw_state *)e->mask;
+
+ ucontrol->value.enumerated.item[0] = ps->cur_mode_id;
+
+ return 0;
+}
+#endif
+#ifndef AIC3XXX_CFW_HOST_BLD
+static int aic3xxx_put_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct cfw_state *ps = (struct cfw_state *)e->mask;
+ struct cfw_asoc_toc *toc;
+ int index, ret;
+
+ aic3xxx_cfw_lock(ps, 1);
+ toc = ps->pjt->asoc_toc;
+
+ index = ucontrol->value.enumerated.item[0];
+ if (index < 0 || index >= toc->nentries) {
+ aic3xxx_cfw_lock(ps, 0);
+ return -EINVAL;
+ }
+ ret =
+ aic3xxx_cfw_setmode_cfg_u(ps, toc->entry[index].mode,
+ toc->entry[index].cfg);
+ aic3xxx_cfw_lock(ps, 0);
+ return ret;
+}
+#endif
+
+int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps)
+{
+#ifndef AIC3XXX_CFW_HOST_BLD
+ int j;
+ struct cfw_asoc_toc *toc = ps->pjt->asoc_toc;
+ struct soc_enum *mode_cfg_enum =
+ kzalloc(sizeof(struct soc_enum), GFP_KERNEL);
+ struct snd_kcontrol_new *mode_cfg_control =
+ kzalloc(sizeof(struct snd_kcontrol_new), GFP_KERNEL);
+ char **enum_texts;
+
+ if (mode_cfg_enum == NULL)
+ goto mem_err;
+ if (mode_cfg_control == NULL)
+ goto mem_err;
+
+ mode_cfg_enum->texts =
+ kzalloc(toc->nentries * sizeof(char *), GFP_KERNEL);
+ if (mode_cfg_enum->texts == NULL)
+ goto mem_err;
+ /* Hack to overwrite the const * const pointer */
+ enum_texts = (char **)mode_cfg_enum->texts;
+
+ for (j = 0; j < toc->nentries; j++)
+ enum_texts[j] = toc->entry[j].etext;
+ mode_cfg_enum->reg = j;
+ mode_cfg_enum->max = toc->nentries;
+ mode_cfg_enum->mask = (unsigned int)ps;
+ mode_cfg_control->name = "Codec Firmware Setmode";
+ mode_cfg_control->get = aic3xxx_get_mode;
+ mode_cfg_control->put = aic3xxx_put_mode;
+ mode_cfg_control->info = snd_soc_info_enum_ext;
+ mode_cfg_control->private_value = (unsigned long)mode_cfg_enum;
+ mode_cfg_control->iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ snd_soc_add_controls(codec, mode_cfg_control, 1);
+ return 0;
+mem_err:
+ kfree(mode_cfg_control);
+ kfree(mode_cfg_enum);
+ kfree(mode_cfg_enum->texts);
+ return -ENOMEM;
+#else
+ return 0;
+#endif
+
+}
diff --git a/sound/soc/codecs/aic3xxx_cfw_ops.h b/sound/soc/codecs/aic3xxx_cfw_ops.h
new file mode 100644
index 000000000000..81f6bda3581b
--- /dev/null
+++ b/sound/soc/codecs/aic3xxx_cfw_ops.h
@@ -0,0 +1,76 @@
+#ifndef AIC3XXX_CFW_OPS_H_
+#define AIC3XXX_CFW_OPS_H_
+#define DEBUG
+#ifdef AIC3XXX_CFW_HOST_BLD
+struct mutex {
+ int lock;
+};
+#endif
+
+struct cfw_state {
+ struct cfw_project *pjt;
+ struct aic3xxx_codec_ops const *ops;
+ void *ops_obj;
+ struct mutex mutex;
+ int cur_mode_id;
+ int cur_mode;
+ int cur_pfw;
+ int cur_ovly;
+ int cur_cfg;
+};
+
+#ifdef AIC3XXX_CFW_HOST_BLD
+struct cfw_project *aic3xxx_cfw_unpickle(void *pcfw, int n);
+unsigned int crc32(unsigned int *pdata, int n);
+struct snd_soc_codec;
+#else
+#ifdef DEBUG
+#define DBG(fmt, ...) printk(KERN_DEBUG "CFW[%s:%d]: " fmt "\n", \
+ __FILE__, __LINE__, ##__VA_ARGS__)
+#else
+ #define DBG(fmt, ...)
+#endif
+#endif
+int aic3xxx_cfw_init(struct cfw_state *ps, struct aic3xxx_codec_ops const *ops,
+ void *ops_obj);
+int aic3xxx_cfw_lock(struct cfw_state *ps, int lock);
+int aic3xxx_cfw_reload(struct cfw_state *ps, void *pcfw, int n);
+int aic3xxx_cfw_setmode(struct cfw_state *ps, int mode);
+int aic3xxx_cfw_setmode_cfg(struct cfw_state *ps, int mode, int cfg);
+int aic3xxx_cfw_setcfg(struct cfw_state *ps, int cfg);
+int aic3xxx_cfw_transition(struct cfw_state *ps, char *ttype);
+int aic3xxx_cfw_set_pll(struct cfw_state *ps, int asi);
+int aic3xxx_cfw_control(struct cfw_state *ps, char *cname, int param);
+int aic3xxx_cfw_add_controls(struct snd_soc_codec *codec, struct cfw_state *ps);
+int aic3xxx_cfw_add_modes(struct snd_soc_codec *codec, struct cfw_state *ps);
+
+
+#define AIC3XX_COPS_MDSP_D (0x00000003u)
+#define AIC3XX_COPS_MDSP_A (0x00000030u)
+#define AIC3XX_COPS_MDSP_ALL (AIC3XX_COPS_MDSP_D|AIC3XX_COPS_MDSP_A)
+
+#define AIC3XX_ABUF_MDSP_D1 (0x00000001u)
+#define AIC3XX_ABUF_MDSP_D2 (0x00000002u)
+#define AIC3XX_ABUF_MDSP_A (0x00000010u)
+#define AIC3XX_ABUF_MDSP_ALL \
+ (AIC3XX_ABUF_MDSP_D1 | AIC3XX_ABUF_MDSP_D2 | AIC3XX_ABUF_MDSP_A)
+
+struct aic3xxx_codec_ops {
+ int (*reg_read)(void *p, unsigned int reg);
+ int (*reg_write)(void *p, unsigned int reg,
+ unsigned int val);
+ int (*set_bits)(void *p, unsigned int reg,
+ unsigned char mask, unsigned char val);
+ int (*bulk_read)(void *p, unsigned int reg,
+ int count, u8 *buf);
+ int (*bulk_write)(void *p, unsigned int reg,
+ int count, const u8 *buf);
+
+ int (*lock) (void *p);
+ int (*unlock) (void *p);
+ int (*stop) (void *p, int mask);
+ int (*restore) (void *p, int runstate);
+ int (*bswap) (void *p, int mask);
+};
+
+#endif
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index b2b31f912b74..31ca26388642 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -389,7 +389,7 @@ static struct {
{ 0xFF, 0xFF, 0 }, /* 2C right SPK mixer */
{ 0xFF, 0xFF, 0 }, /* 2D SPK control */
{ 0xFF, 0xFF, 0 }, /* 2E sidetone */
- { 0xFF, 0xFF, 0 }, /* 2F DAI1 playback level */
+ { 0xFF, 0xFF, 1 }, /* 2F DAI1 playback level */
{ 0xFF, 0xFF, 0 }, /* 30 DAI1 playback level */
{ 0xFF, 0xFF, 0 }, /* 31 DAI2 playback level */
diff --git a/sound/soc/codecs/tlv320aic3262_default_fw.h b/sound/soc/codecs/tlv320aic3262_default_fw.h
new file mode 100644
index 000000000000..7c1842f0f65f
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3262_default_fw.h
@@ -0,0 +1,582 @@
+unsigned char default_firmware[] = {
+ 237, 241, 209, 192, 179, 0, 1, 0, 58, 36, 0, 0, 37, 131, 58, 238,
+ 0, 0, 0, 0, 8, 207, 52, 80, 70, 105, 114, 109, 119, 97, 114, 101,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 13, 0, 0, 8, 2, 0, 0,
+ 168, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 2, 0, 16, 6, 0, 0, 251, 17, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 230, 29, 0, 0, 54, 32, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 134, 34, 0, 0, 105, 110, 105, 116, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 73, 110, 105, 116, 105, 97, 108, 105,
+ 122, 97, 116, 105, 111, 110, 32, 115, 101, 113, 117, 101, 110, 99, 101,
+ 32, 40, 97, 112, 112, 108, 105, 101, 100, 32, 111, 110, 108, 121,
+ 32, 111, 110, 32, 115, 121, 115, 116, 101, 109, 32, 98, 111, 111,
+ 116, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 236, 5, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 100, 0, 128, 0, 0, 1, 1, 0, 0, 1, 122, 1,
+ 0, 0, 4, 51, 0, 0, 82, 0, 0, 0, 67, 151, 0, 1, 119, 127,
+ 100, 101, 102, 97, 117, 108, 116, 77, 117, 115, 105, 99, 0, 109, 97,
+ 105, 110, 95, 82, 97, 116, 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 53, 12, 0, 0, 172, 9, 0, 0, 233, 12, 0, 0,
+ 114, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 101, 102, 97,
+ 117, 108, 116, 47, 98, 97, 115, 101, 95, 109, 97, 105, 110, 95, 82, 97,
+ 116, 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 128, 0, 0, 0, 1, 0, 0, 0, 44, 12, 0, 0, 2, 0, 0, 0,
+ 0, 0, 60, 1, 1, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 129,
+ 127, 0, 0, 6, 17, 0, 0, 129, 63, 0, 0, 7, 8, 0, 0, 8,
+ 0, 0, 0, 9, 0, 0, 0, 129, 127, 0, 0, 10, 1, 0, 0, 129,
+ 127, 0, 0, 11, 2, 0, 0, 129, 127, 0, 0, 12, 8, 0, 0, 13,
+ 0, 0, 0, 14, 128, 0, 0, 129, 127, 0, 0, 18, 2, 0, 0, 129,
+ 127, 0, 0, 19, 16, 0, 0, 20, 64, 0, 0, 129, 3, 0, 4, 11,
+ 1, 0, 0, 129, 127, 0, 4, 12, 4, 0, 0, 129, 127, 0, 4, 13,
+ 32, 0, 0, 129, 119, 0, 4, 14, 2, 0, 0, 129, 3, 0, 4, 27,
+ 1, 0, 0, 129, 127, 0, 4, 28, 4, 0, 0, 129, 127, 0, 4, 29,
+ 32, 0, 0, 129, 119, 0, 4, 30, 32, 0, 0, 129, 3, 0, 4, 43,
+ 1, 0, 0, 129, 127, 0, 4, 44, 4, 0, 0, 129, 127, 0, 4, 45,
+ 32, 0, 0, 129, 119, 0, 4, 46, 64, 98, 97, 115, 101, 95, 109, 97,
+ 105, 110, 0, 116, 99, 104, 95, 98, 97, 115, 101, 95, 109, 97, 105, 110,
+ 95, 82, 97, 116, 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 93, 15, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0,
+ 0, 1, 0, 0, 0, 105, 15, 0, 0, 2, 0, 0, 0, 0, 0, 60,
+ 1, 1, 98, 97, 115, 101, 95, 115, 112, 107, 0, 97, 116, 99, 104, 95,
+ 98, 97, 115, 101, 95, 115, 112, 107, 95, 82, 97, 116, 101, 52, 56, 46,
+ 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 230, 17, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 1, 0, 0, 0, 242, 17,
+ 0, 0, 2, 0, 0, 0, 0, 0, 60, 1, 1, 100, 101, 102, 97, 117,
+ 108, 116, 86, 111, 105, 99, 101, 0, 109, 97, 105, 110, 95, 82, 97, 116,
+ 101, 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 32,
+ 24, 0, 0, 151, 21, 0, 0, 212, 24, 0, 0, 93, 27, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 100, 101, 102, 97, 117, 108, 116, 47, 98,
+ 97, 115, 101, 95, 109, 97, 105, 110, 95, 82, 97, 116, 101, 52, 56, 46,
+ 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 24, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 1,
+ 0, 0, 0, 23, 24, 0, 0, 2, 0, 0, 0, 0, 0, 60, 1, 1,
+ 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 129, 127, 0, 0, 6, 17,
+ 0, 0, 129, 63, 0, 0, 7, 8, 0, 0, 8, 0, 0, 0, 9, 0,
+ 0, 0, 129, 127, 0, 0, 10, 1, 0, 0, 129, 127, 0, 0, 11, 8,
+ 0, 0, 129, 127, 0, 0, 12, 2, 0, 0, 13, 3, 0, 0, 14, 0,
+ 0, 0, 129, 127, 0, 0, 18, 8, 0, 0, 129, 127, 0, 0, 19, 12,
+ 0, 0, 20, 128, 0, 0, 129, 3, 0, 4, 11, 1, 0, 0, 129, 127,
+ 0, 4, 12, 4, 0, 0, 129, 127, 0, 4, 13, 32, 0, 0, 129, 119,
+ 0, 4, 14, 2, 0, 0, 129, 3, 0, 4, 27, 1, 0, 0, 129, 127,
+ 0, 4, 28, 24, 0, 0, 129, 127, 0, 4, 29, 32, 0, 0, 129, 119,
+ 0, 4, 30, 36, 0, 0, 129, 3, 0, 4, 43, 1, 0, 0, 129, 127,
+ 0, 4, 44, 4, 0, 0, 129, 127, 0, 4, 45, 32, 0, 0, 129, 119,
+ 0, 4, 46, 64, 98, 97, 115, 101, 95, 109, 97, 105, 110, 0, 116, 99,
+ 104, 95, 98, 97, 115, 101, 95, 109, 97, 105, 110, 95, 82, 97, 116, 101,
+ 52, 56, 46, 99, 102, 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 72, 27, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, 0, 1, 0, 0, 0,
+ 84, 27, 0, 0, 2, 0, 0, 0, 0, 0, 60, 1, 1, 98, 97, 115,
+ 101, 95, 115, 112, 107, 0, 97, 116, 99, 104, 95, 98, 97, 115, 101, 95,
+ 115, 112, 107, 95, 82, 97, 116, 101, 52, 56, 46, 99, 102, 103, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 209, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 128, 0, 0, 0, 1, 0, 0, 0, 221, 29, 0, 0, 2, 0, 0,
+ 0, 0, 0, 60, 1, 1, 100, 101, 102, 97, 117, 108, 116, 77, 117, 115,
+ 105, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 100, 101, 102, 97, 117, 108, 116, 86, 111, 105,
+ 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 100, 101, 102, 97, 117, 108,
+ 116, 77, 117, 115, 105, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 100, 101, 102, 97, 117, 108, 116, 77, 117, 115, 105, 99, 32, 98,
+ 97, 115, 101, 95, 109, 97, 105, 110, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 101, 102, 97, 117, 108,
+ 116, 77, 117, 115, 105, 99, 32, 98, 97, 115, 101, 95, 115, 112, 107, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 100, 101, 102, 97, 117, 108, 116, 86, 111, 105, 99, 101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 100, 101, 102, 97, 117, 108,
+ 116, 86, 111, 105, 99, 101, 32, 98, 97, 115, 101, 95, 109, 97, 105,
+ 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 100, 101, 102, 97, 117, 108, 116, 86, 111, 105, 99, 101, 32, 98,
+ 97, 115, 101, 95, 115, 112, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+};
diff --git a/sound/soc/codecs/tlv320aic326x.c b/sound/soc/codecs/tlv320aic326x.c
index 5d6b92904d56..06f813bbc0ca 100644
--- a/sound/soc/codecs/tlv320aic326x.c
+++ b/sound/soc/codecs/tlv320aic326x.c
@@ -1,636 +1,198 @@
/*
-* linux/sound/soc/codecs/tlv320aic3262.c
-*
-* Copyright (C) 2012 Texas Instruments, Inc.
-*
-* Based on sound/soc/codecs/tlv320aic3262.c
-*
-* This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
-* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
-* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-*
-* The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
-* codec with digital microphone inputs and programmable outputs.
-*
-* History:
-*
-* Rev 0.1 ASoC driver support 20-01-2011
-*
-* The AIC325x ASoC driver is ported for the codec AIC3262.
-* Rev 0.2 ASoC driver support 21-03-2011
-* The AIC326x ASoC driver is updated abe changes.
-*
-* Rev 0.3 ASoC driver support 12.09.2011
-* fixed the compilation issues for Whistler support
-*
-* Rev 0.4 ASoC driver support 27.09.2011
-* The AIC326x driver ported for Nvidia cardhu.
-*
-* Rev 0.5 Modified to support Multiple ASI Ports 08-Nov-2011
-* Driver updated to support ASI Ports of AIC3262
-*
-* Modified by Nvidia 23-Nov-2011 for K39 ASoC changes.
-*/
+ * linux/sound/soc/codecs/tlv320aic326x.c
+ *
+ * Copyright (C) 2011 Texas Instruments Inc.,
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
+ * codec with digital microphone inputs and programmable outputs.
+ *
+ * History:
+ *
+ * Rev 0.1 ASoC driver support TI 20-01-2011
+ *
+ * The AIC325x ASoC driver is ported for the codec AIC3262.
+ * Rev 0.2 ASoC driver support TI 21-03-2011
+ * The AIC326x ASoC driver is updated for linux 2.6.32 Kernel.
+ * Rev 0.3 ASoC driver support TI 20-04-2011
+ * The AIC326x ASoC driver is ported to 2.6.35 omap4 kernel
+ */
/*
*****************************************************************************
* INCLUDES
*****************************************************************************
*/
+
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/platform_device.h>
+#include <linux/switch.h>
+#include <sound/jack.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+
+#include <sound/tlv.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
-#include <sound/tlv.h>
-#include <asm/div64.h>
-#include <sound/tlv320aic326x.h>
-#include <sound/jack.h>
-#include <linux/spi/spi.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
+#include <linux/mfd/tlv320aic3262-core.h>
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
#include "tlv320aic326x.h"
-#include <linux/gpio.h>
-/*
- *****************************************************************************
- * Global Variable
- *****************************************************************************
- */
-static u8 aic3262_reg_ctl;
-
-#ifdef AIC3262_TiLoad
- extern int aic3262_driver_init(struct snd_soc_codec *codec);
-#endif
-
+#include "aic3262_codec_ops.h"
+#include "tlv320aic3262_default_fw.h"
-/* whenever aplay/arecord is run, aic3262_hw_params() function gets called.
- * 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 struct snd_soc_codec *aic3262_codec;
-
-/*
- *****************************************************************************
- * Macros
- *****************************************************************************
- */
-
-/* ASoC Widget Control definition for a single Register based Control */
-#define SOC_SINGLE_AIC3262(xname) \
-{\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = __new_control_info, .get = __new_control_get,\
- .put = __new_control_put, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-}
-#define SOC_SINGLE_N(xname, xreg, xshift, xmax, xinvert) \
-{\
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = n_control_info, .get = n_control_get,\
- .put = n_control_put, \
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .private_value = ((unsigned long)&(struct soc_mixer_control)) \
- {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
- .invert = xinvert} }
-
-/* ASoC Widget Control definition for a Double Register based Control */
-
-#define SOC_DOUBLE_R_N(xname, reg_left, reg_right, xshift, xmax, xinvert) \
+#define SOC_DOUBLE_R_SX_TLV3262(xname, xreg_left, xreg_right, xshift,\
+ xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .info = snd_soc_info_volsw_2r_n, \
- .get = snd_soc_get_volsw_2r_n, .put = snd_soc_put_volsw_2r_n, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = reg_left, .rreg = reg_right, .shift = xshift, \
- .max = xmax, .invert = xinvert} }
-
-#define SND_SOC_DAPM_SWITCH_N(wname, wreg, wshift, winvert) \
-{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift,\
- .invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
-/*
- *****************************************************************************
- * Function Prototype
- *****************************************************************************
- */
-static int aic3262_set_bias_level(struct snd_soc_codec *codec,
- enum snd_soc_bias_level level);
-
-static int __new_control_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo);
-
-static int __new_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-
-static int __new_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-
-static inline int aic3262_get_divs(int mclk, int rate);
-
-static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai);
-
-static int aic3262_multi_i2s_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir);
-static int aic3262_multi_i2s_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, int source, unsigned int freq_in,
- unsigned int freq_out);
-
-static int aic3262_multi_i2s_asi1_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt);
-
-static int aic3262_multi_i2s_asi2_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt);
-
-static int aic3262_multi_i2s_asi3_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt);
-
-static int aic3262_multi_i2s_asi1_mute(struct snd_soc_dai *dai, int mute);
-
-static int aic3262_multi_i2s_asi2_mute(struct snd_soc_dai *dai, int mute);
-
-static int aic3262_multi_i2s_asi3_mute(struct snd_soc_dai *dai, int mute);
-
-#if 0
-static const char *wclk1_pincontrol[] = {
- "ASI1 Word Clock Input/Output", "CLKOUT output"};
-static const char *dout1_pincontrol[] = {
- "disabled", "ASI1 data output", "gpio", "clock out",
- "INT1", "INT2", "SAR ADC interrupt"};
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw_2r_sx, \
+ .get = snd_soc_get_volsw_2r_sx, \
+ .put = snd_soc_put_volsw_2r_sx_aic3262, \
+ .private_value = (unsigned long) &(struct soc_mixer_control) \
+ {.reg = xreg_left, \
+ .rreg = xreg_right, .shift = xshift, \
+ .min = xmin, .max = xmax} }
-static const char *din1_pincontrol[] = {"disabled", "enabled"};
+/*****************************************************************************
+ Macros
+******************************************************************************
-static const char *wclk2_pincontrol[] = {
- "diabled", "ASI1 secondary wclk", "general purpose input",
- "general purpose output", "clkout", "INT1 interrupt",
- "IN2 interrupt", "output digital microphone",
- "SAR ADC interrupt", "data output for ASI1"};
+******************************************************************************
+ Function Prototype
+******************************************************************************/
-static const char *bclk2_pincontrol[] = {
- "diabled", "ASI1 secondary wclk", "general purpose input",
- "general purpose output", "clkout", "INT1 interrupt",
- "IN2 interrupt", "output digital microphone",
- "SAR ADC interrupt", "data output for ASI1"};
+static int aic3262_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai);
-static const char *dout2_pincontrol[] = {
- "disabled", "ASI2 Data Output", "General Purpose Output",
- "INT1 Interrupt", "INT2 Interrupt", "SAR ADC interrupt",
- "Output for digital microphone", "Data Output for ASI1"};
+static int aic3262_mute(struct snd_soc_dai *dai, int mute);
-static const char *din2_pincontrol[] = {"disabled", "enabled"};
+static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir);
-static const char *wclk3_pincontrol[] = {
- "Disabled", "ASI3 WCLK", "General Purpose Input",
- "General Purpose output", "Data Output for ASI1"};
+static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt);
-static const char *bclk3_pincontrol[] = {
- "Disabled", "ASI3 BCLK", "General Purpose Input",
- "General Purpose output", "Data Output for ASI1"};
+static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int Fin, unsigned int Fout);
-static const char *dout3_pincontrol[] = {
- "disabled", "ASI3 data ooutput", "General Purpose Output",
- "ASI1 Word Clock Output", "Data Output for ASI1"};
-
-static const char *din3_pincontrol[] = {"disabled", "enabled"};
-
-static const char *clkin[] = {
- "mclk1", "bclk1", "gpio1", "pll_clk", "bclk2", "gpi1",
- "hf_ref_clk", "hf_osc_clk", "mclk2", "gpio2", "gpi2"};
-
-#endif
-#ifdef DAC_INDEPENDENT_VOL
-/*
- *----------------------------------------------------------------------------
- * Function : n_control_info
- * Purpose : This function is to initialize data for new control required to
- * program the AIC3262 registers.
- *
- *----------------------------------------------------------------------------
- */
-static int n_control_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
-
- if (max == 1)
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- else
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-
- uinfo->count = shift == rshift ? 1 : 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = max;
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------------
- * Function : n_control_get
- * Purpose : This function is to read data of new control for
- * program the AIC3262 registers.
- *
- *----------------------------------------------------------------------------
- */
-static int n_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- u32 val;
- unsigned short mask, shift;
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- if (!strcmp(kcontrol->id.name, "Left DAC Volume")) {
- mask = AIC3262_8BITS_MASK;
- shift = 0;
- val = snd_soc_read(codec, mc->reg);
- ucontrol->value.integer.value[0] =
- (val <= 48) ? (val + 127) : (val - 129);
- }
- if (!strcmp(kcontrol->id.name, "Right DAC Volume")) {
- mask = AIC3262_8BITS_MASK;
- shift = 0;
- val = snd_soc_read(codec, mc->reg);
- ucontrol->value.integer.value[0] =
- (val <= 48) ? (val + 127) : (val - 129);
- }
+static int aic3262_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level);
- return 0;
-}
+static int aic3262_set_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
-/*
- *----------------------------------------------------------------------------
- * Function : __new_control_put
- * Purpose : new_control_put is called to pass data from user/application to
- * the driver.
- *
- *----------------------------------------------------------------------------
- */
-static int n_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- u8 val, val_mask;
- int reg, err;
- unsigned int invert = mc->invert;
- int max = mc->max;
- DBG("n_control_put\n");
- reg = mc->reg;
- val = ucontrol->value.integer.value[0];
- if (invert)
- val = max - val;
- if (!strcmp(kcontrol->id.name, "Left DAC Volume")) {
- DBG("LDAC\n");
- val = (val >= 127) ? (val - 127) : (val + 129);
- val_mask = AIC3262_8BITS_MASK;
- }
- if (!strcmp(kcontrol->id.name, "Right DAC Volume")) {
- DBG("RDAC\n");
- val = (val >= 127) ? (val - 127) : (val + 129);
- val_mask = AIC3262_8BITS_MASK;
- }
+static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event);
- err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
- if (err < 0) {
- printk(KERN_ERR "Error while updating bits\n");
- return err;
- }
+static long debug_level;
+module_param(debug_level, long, 0);
+MODULE_PARM_DESC(debug_level, "Debug level for printing");
- return 0;
-}
-#endif /*#ifdef DAC_INDEPENDENT_VOL*/
-/*
- *------------------------------------------------------------------------------
- * snd_soc_info_volsw_2r_n - double mixer info callback
+/**
+ * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
+ * mixer put callback
* @kcontrol: mixer control
* @uinfo: control element information
*
- * Callback to provide information about a double mixer control that
- * spans 2 codec registers.
- *
* Returns 0 for success.
- *------------------------------------------------------------------------------
*/
-int snd_soc_info_volsw_2r_n(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+int snd_soc_put_volsw_2r_sx_aic3262(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max;
-
- if (max == 1)
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- else
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = max;
- return 0;
-}
-
-/*
- *------------------------------------------------------------------------------
- * snd_soc_get_volsw_2r_n - double mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a double mixer control that spans 2 registers.
- *
- * Returns 0 for success.
- *------------------------------------------------------------------------------
- */
-int snd_soc_get_volsw_2r_n(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
+ (struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- int max = mc->max;
- unsigned int mask;
- unsigned int invert = mc->invert;
- unsigned short val, val2;
-
- if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) {
- mask = AIC3262_8BITS_MASK;
- shift = 0;
- } else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) {
- mask = 0x3F;
- shift = 0;
- } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
- mask = 0x7F;
- shift = 0;
- } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) {
- mask = 0x3F;
- shift = 0;
- } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) {
- mask = 0x7F;
- shift = 0;
- } else if (!strcmp(kcontrol->id.name, "MA Volume")) {
- mask = 0x7F;
- shift = 0;
- } else {
- printk(KERN_ERR "Invalid kcontrol name\n");
- return -1;
- }
-
- /* Read, update the corresponding Registers */
- val = (snd_soc_read(codec, reg) >> shift) & mask;
- val2 = (snd_soc_read(codec, reg2) >> shift) & mask;
-
- if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) {
- ucontrol->value.integer.value[0] =
- (val <= 48) ? (val + 127) : (val - 129);
- ucontrol->value.integer.value[1] =
- (val2 <= 48) ? (val2 + 127) : (val2 - 129);
- } else if (!strcmp(kcontrol->id.name, "HP Driver Gain")) {
- ucontrol->value.integer.value[0] =
- (val >= 57) ? (val - 57) : (val + 7);
- ucontrol->value.integer.value[1] =
- (val2 >= 57) ? (val2 - 57) : (val2 + 7);
- } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
- ucontrol->value.integer.value[0] =
- (val <= 40) ? (val + 24) : (val - 104);
- ucontrol->value.integer.value[1] =
- (val2 <= 40) ? (val2 + 24) : (val2 - 104);
- } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) {
- ucontrol->value.integer.value[0] = ((val >= 0) & (val <= 29)) ?
- (val + 7) : (val - 57);
- ucontrol->value.integer.value[1] = ((val2 >= 0) &
- (val2 <= 29)) ? (val2 + 7) : (val2 - 57);
-
- } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) {
- ucontrol->value.integer.value[0] = ((val >= 0) & (val <= 116)) ?
- (val + 1) : ((val == 127) ? (0) : (117));
- ucontrol->value.integer.value[1] = ((val2 >= 0) & (val2 <= 116))
- ? (val2 + 1) : ((val2 == 127) ? (0) : (117));
-
- } else if (!strcmp(kcontrol->id.name, "MA Volume")) {
- ucontrol->value.integer.value[0] = (val <= 40) ?
- (41 - val) : (val = 0);
- ucontrol->value.integer.value[1] = (val2 <= 40) ?
- (41 - val2) : (val2 = 0);
- }
-
- if (invert) {
- ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- }
-
- return 0;
-}
-/*
-*-------------------------------------------------------------------------------
-* snd_soc_put_volsw_2r_n - double mixer set callback
-* @kcontrol: mixer control
-* @ucontrol: control element information
-*
-* Callback to set the value of a double mixer control that spans 2 registers.
-*
-* Returns 0 for success.
-*-------------------------------------------------------------------------------
-*/
-int snd_soc_put_volsw_2r_n(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- int max = mc->max;
- unsigned int mask;
- unsigned int invert = mc->invert;
- int err;
- unsigned short val, val2, val_mask;
-
- mask = 0x00FF;
-
- val = (ucontrol->value.integer.value[0] & mask);
- val2 = (ucontrol->value.integer.value[1] & mask);
- if (invert) {
- val = max - val;
- val2 = max - val2;
- }
-
- /* Check for the string name of the kcontrol */
- if (!strcmp(kcontrol->id.name, "PCM Playback Volume")) {
- val = (val >= 127) ? (val - 127) : (val + 129);
- val2 = (val2 >= 127) ? (val2 - 127) : (val2 + 129);
- val_mask = AIC3262_8BITS_MASK; /* 8 bits */
- } else if ((!strcmp(kcontrol->id.name, "HP Driver Gain")) ||
- (!strcmp(kcontrol->id.name, "LO Driver Gain"))) {
- val = (val <= 6) ? (val + 57) : (val - 7);
- val2 = (val2 <= 6) ? (val2 + 57) : (val2 - 7);
- val_mask = 0x3F; /* 6 bits */
- DBG("val=%d, val2=%d", val, val2);
- } else if (!strcmp(kcontrol->id.name, "PGA Capture Volume")) {
- val = (val >= 24) ? ((val <= 64) ?
- (val-24) : (40)) : (val + 104);
- val2 = (val2 >= 24) ?
- ((val2 <= 64) ? (val2 - 24) : (40)) : (val2 + 104);
- val_mask = 0x7F; /* 7 bits */
- } else if (!strcmp(kcontrol->id.name, "LO to REC Volume")) {
-
- val = (val <= 116) ?
- (val % 116) : ((val == 117) ? (127) : (117));
- val2 = (val2 <= 116) ?
- (val2 % 116) : ((val2 == 117) ? (127) : (117));
- val_mask = 0x7F;
- } else if (!strcmp(kcontrol->id.name, "REC Driver Volume")) {
-
- val = (val <= 7) ? (val + 57) : ((val < 36) ? (val - 7) : (29));
- val2 = (val2 <= 7) ?
- (val2 + 57) : ((val2 < 36) ? (val2 - 7) : (29));
- val_mask = 0x3F;
- } else if (!strcmp(kcontrol->id.name, "LO to HP Volume")) {
-
- val = ((val > 0) & (val <= 117)) ?
- (val - 1) : ((val == 0) ? (127) : (116));
- val2 = ((val2 > 0) & (val2 <= 117)) ?
- (val2 - 1) : ((val2 == 0) ? (127) : (116));
- val_mask = 0x7F;
- } else if (!strcmp(kcontrol->id.name, "MA Volume")) {
-
- val = ((val <= 41) & (val > 0)) ?
- (41 - val) : ((val > 41) ? (val = 41) : (63));
- val2 = ((val2 <= 41) & (val2 > 0)) ?
- (41 - val2) : ((val2 > 41) ? (val2 = 41) : (63));
- val_mask = 0x7F;
- } else {
- printk(KERN_ERR "Invalid control name\n");
- return -1;
- }
-
- val = val << shift;
- val2 = val2 << shift;
-
- err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
- if (err < 0)
- return err;
+ unsigned int mask = (1 << mc->shift) - 1;
+ int min = mc->min;
+ int ret;
+ unsigned int val, valr;
- err = snd_soc_update_bits_locked(codec, reg2, val_mask, val2);
- return err;
-}
-
-static int __new_control_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 65535;
+ val = ((ucontrol->value.integer.value[0] + min) & 0xff);
+ val &= mask;
+ valr = ((ucontrol->value.integer.value[1] + min) & 0xff);
+ valr &= mask;
+ ret = 0;
+ ret = snd_soc_update_bits_locked(codec, mc->reg, mask, val);
+ if (ret < 0)
+ return ret;
+ ret = snd_soc_update_bits_locked(codec, mc->rreg, mask, valr);
+ if (ret < 0)
+ return ret;
return 0;
}
-/*
- *----------------------------------------------------------------------------
- * Function : __new_control_get
- * Purpose : This function is to read data of new control for
- * program the AIC3262 registers.
- *
- *----------------------------------------------------------------------------
- */
-static int __new_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static ssize_t debug_level_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf, size_t count)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- u32 val;
- val = snd_soc_read(codec, aic3262_reg_ctl);
- ucontrol->value.integer.value[0] = val;
- return 0;
+ return sprintf(buf, "%ld\n", debug_level);
}
-/*
- *----------------------------------------------------------------------------
- * Function : __new_control_put
- * Purpose : new_control_put is called to pass data from user/application to
- * the driver.
- *
- *----------------------------------------------------------------------------
- */
-static int __new_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static ssize_t debug_level_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 data[2];
- int ret = 0;
-
- u32 data_from_user = ucontrol->value.integer.value[0];
-
- aic3262_change_book(codec, 0);
- aic3262_reg_ctl = data[0] = (u8) ((data_from_user & 0xFF00) >> 8);
- data[1] = (u8) ((data_from_user & 0x00FF));
-
- if (!data[0])
- aic3262->page_no = data[1];
+ int ret;
- DBG("reg = %d val = %x\n", data[0], data[1]);
-#if defined(LOCAL_REG_ACCESS)
- if (codec->hw_write(codec->control_data, data, 2) != 2)
- ret = -EIO;
-#else
- ret = snd_soc_write(codec, data[0], data[1]);
-#endif
+ ret = kstrtol(buf, 10, &debug_level);
if (ret)
- printk(KERN_ERR "Error in i2c write\n");
-
- return ret;
+ return ret;
+ return count;
}
+static DEVICE_ATTR(debug_level, 0644, debug_level_show, debug_level_set);
-/*
- *****************************************************************************
- * Structure Initialization
- *****************************************************************************
- */
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1200, 50, 0);
static const DECLARE_TLV_DB_SCALE(spk_gain_tlv, 600, 600, 0);
-static const DECLARE_TLV_DB_SCALE(output_gain_tlv, -600, 100, 0);
+static const DECLARE_TLV_DB_SCALE(output_gain_tlv, -600, 100, 1);
static const DECLARE_TLV_DB_SCALE(micpga_gain_tlv, 0, 50, 0);
static const DECLARE_TLV_DB_SCALE(adc_fine_gain_tlv, -40, 10, 0);
static const DECLARE_TLV_DB_SCALE(beep_gen_volume_tlv, -6300, 100, 0);
/* Chip-level Input and Output CM Mode Controls */
-static const char *input_common_mode_text[] = {
- "0.9v", "0.75v" };
+static const char * const input_common_mode_text[] = {
+ "0.9v", "0.75v"
+};
-static const char *output_common_mode_text[] = {
- "Input CM", "1.25v", "1.5v", "1.65v" };
+static const char * const output_common_mode_text[] = {
+ "Input CM", "1.25v", "1.5v", "1.65v"
+};
static const struct soc_enum input_cm_mode =
- SOC_ENUM_SINGLE(CM_REG, 2, 2, input_common_mode_text);
+SOC_ENUM_SINGLE(AIC3262_CM_REG, 2, 2, input_common_mode_text);
static const struct soc_enum output_cm_mode =
- SOC_ENUM_SINGLE(CM_REG, 0, 4, output_common_mode_text);
-
+SOC_ENUM_SINGLE(AIC3262_CM_REG, 0, 4, output_common_mode_text);
/*
*****************************************************************************
* Structure Initialization
@@ -641,2388 +203,874 @@ static const struct snd_kcontrol_new aic3262_snd_controls[] = {
#ifndef DAC_INDEPENDENT_VOL
/* sound new kcontrol for PCM Playback volume control */
- SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
- DAC_LVOL, DAC_RVOL, 8,0xffffff81, 0x30, dac_vol_tlv),
+ SOC_DOUBLE_R_SX_TLV3262("PCM Playback Volume",
+ AIC3262_DAC_LVOL, AIC3262_DAC_RVOL, 8,
+ 0xffffff81,
+ 0x30, dac_vol_tlv),
#endif
- /*HP Driver Gain Control*/
- SOC_DOUBLE_R_SX_TLV("HeadPhone Driver Amplifier Volume",
- HPL_VOL, HPR_VOL, 6, 0xfffffffa, 0xe, output_gain_tlv),
-
- /*LO Driver Gain Control*/
- SOC_DOUBLE_TLV("Speaker Amplifier Volume",
- SPK_AMP_CNTL_R4, 4, 0, 5, 0, spk_gain_tlv),
+ /*HP Driver Gain Control */
+ SOC_DOUBLE_R_SX_TLV3262("HeadPhone Driver Amplifier Volume",
+ AIC3262_HPL_VOL, AIC3262_HPR_VOL, 6, 0xffffffb9,
+ 0xffffffce, output_gain_tlv),
+ /*LO Driver Gain Control */
+ SOC_DOUBLE_TLV("Speaker Amplifier Volume", AIC3262_SPK_AMP_CNTL_R4, 4,
+ 0, 5, 0, spk_gain_tlv),
- SOC_DOUBLE_R_SX_TLV("Receiver Amplifier Volume",
- REC_AMP_CNTL_R5, RAMPR_VOL, 6, 0xfffffffa, 0x1d, output_gain_tlv),
+ SOC_DOUBLE_R_SX_TLV3262("Receiver Amplifier Volume",
+ AIC3262_REC_AMP_CNTL_R5, AIC3262_RAMPR_VOL, 6,
+ 0xffffffb9, 0xffffffd6, output_gain_tlv),
- SOC_DOUBLE_R_SX_TLV("PCM Capture Volume",
- LADC_VOL, RADC_VOL, 7,0xffffff68, 0x24, adc_vol_tlv),
+ SOC_DOUBLE_R_SX_TLV3262("PCM Capture Volume", AIC3262_LADC_VOL,
+ AIC3262_RADC_VOL, 7, 0xffffff68, 0xffffffa8,
+ adc_vol_tlv),
+ SOC_DOUBLE_R_TLV("MicPGA Volume Control", AIC3262_MICL_PGA,
+ AIC3262_MICR_PGA, 0, 0x5F, 0, micpga_gain_tlv),
- SOC_DOUBLE_R_TLV ("MicPGA Volume Control",
- MICL_PGA, MICR_PGA, 0, 0x5F, 0, micpga_gain_tlv),
- SOC_DOUBLE_TLV("PCM Capture Fine Gain Volume",
- ADC_FINE_GAIN, 4, 0, 5, 1, adc_fine_gain_tlv),
+ SOC_DOUBLE_TLV("PCM Capture Fine Gain Volume", AIC3262_ADC_FINE_GAIN,
+ 4, 0, 5, 1, adc_fine_gain_tlv),
- SOC_DOUBLE("ADC channel mute", ADC_FINE_GAIN, 7, 3, 1, 0),
+ SOC_DOUBLE("ADC channel mute", AIC3262_ADC_FINE_GAIN, 7, 3, 1, 0),
- SOC_DOUBLE("DAC MUTE", DAC_MVOL_CONF, 2, 3, 1, 1),
-
- /* sound new kcontrol for Programming the registers from user space */
- SOC_SINGLE_AIC3262("Program Registers"),
-
- SOC_SINGLE("RESET", RESET_REG, 0,1,0),
-
- SOC_SINGLE("DAC VOL SOFT STEPPING", DAC_MVOL_CONF, 0, 2, 0),
-
-#ifdef DAC_INDEPENDENT_VOL
- /*SOC_SINGLE_N("Left DAC Volume", DAC_LVOL, 0, 0xAF, 0),
- SOC_SINGLE_N("Right DAC Volume", DAC_RVOL, 0, 0xAF, 0),*/
-#endif
+ SOC_DOUBLE("DAC MUTE", AIC3262_DAC_MVOL_CONF, 2, 3, 1, 1),
- SOC_SINGLE("DAC AUTO MUTE CONTROL", DAC_MVOL_CONF, 4, 7, 0),
- SOC_SINGLE("RIGHT MODULATOR SETUP", DAC_MVOL_CONF, 7, 1, 0),
+ SOC_SINGLE("RESET", AIC3262_RESET_REG, 0, 1, 0),
- SOC_SINGLE("ADC Volume soft stepping", ADC_CHANNEL_POW, 0, 3, 0),
+ SOC_SINGLE("DAC VOL SOFT STEPPING", AIC3262_DAC_MVOL_CONF, 0, 2, 0),
- SOC_DOUBLE_R("MICPGA enable/disable",MICL_PGA,MICR_PGA,7, 1, 0),
+ SOC_SINGLE("DAC AUTO MUTE CONTROL", AIC3262_DAC_MVOL_CONF, 4, 7, 0),
- SOC_SINGLE("Mic Bias ext independent enable", MIC_BIAS_CNTL, 7, 1, 0),
- SOC_SINGLE("MICBIAS_EXT ON", MIC_BIAS_CNTL, 6, 1, 0),
- SOC_SINGLE("MICBIAS EXT Power Level", MIC_BIAS_CNTL, 4, 3, 0),
+ SOC_SINGLE("RIGHT MODULATOR SETUP", AIC3262_DAC_MVOL_CONF, 7, 1, 0),
- SOC_SINGLE("MICBIAS_INT ON", MIC_BIAS_CNTL, 2, 1, 0),
- SOC_SINGLE("MICBIAS INT Power Level", MIC_BIAS_CNTL, 0, 3, 0),
+ SOC_SINGLE("ADC Volume soft stepping", AIC3262_ADC_CHANNEL_POW,
+ 0, 3, 0),
- SOC_DOUBLE("DRC_EN_CTL", DRC_CNTL_R1, 6, 5, 1, 0),
- SOC_SINGLE("DRC_THRESHOLD_LEVEL", DRC_CNTL_R1, 2, 7, 1),
- SOC_SINGLE("DRC_HYSTERISIS_LEVEL", DRC_CNTL_R1, 0, 7, 0),
+ SOC_SINGLE("Mic Bias ext independent enable", AIC3262_MIC_BIAS_CNTL,
+ 7, 1, 0),
- SOC_SINGLE("DRC_HOLD_LEVEL", DRC_CNTL_R2, 3, 0x0F, 0),
- SOC_SINGLE("DRC_GAIN_RATE", DRC_CNTL_R2, 0, 4, 0),
- SOC_SINGLE("DRC_ATTACK_RATE", DRC_CNTL_R3, 4, 0x0F, 1),
- SOC_SINGLE("DRC_DECAY_RATE", DRC_CNTL_R3, 0, 0x0F, 1),
+ SOC_SINGLE("MICBIAS EXT Power Level", AIC3262_MIC_BIAS_CNTL, 4, 3, 0),
- SOC_SINGLE("BEEP_GEN_EN", BEEP_CNTL_R1, 7, 1, 0),
- SOC_DOUBLE_R("BEEP_VOL_CNTL", BEEP_CNTL_R1, BEEP_CNTL_R2, 0, 0x0F, 1),
- SOC_SINGLE("BEEP_MAS_VOL", BEEP_CNTL_R2, 6, 3, 0),
+ SOC_SINGLE("MICBIAS INT Power Level", AIC3262_MIC_BIAS_CNTL, 0, 3, 0),
- SOC_DOUBLE_R("AGC_EN", LAGC_CNTL, RAGC_CNTL, 7, 1, 0),
- SOC_DOUBLE_R("AGC_TARGET_LEVEL", LAGC_CNTL, RAGC_CNTL, 4, 7, 1),
+ SOC_SINGLE("BEEP_GEN_EN", AIC3262_BEEP_CNTL_R1, 7, 1, 0),
- SOC_DOUBLE_R("AGC_GAIN_HYSTERESIS", LAGC_CNTL, RAGC_CNTL, 0, 3, 0),
- SOC_DOUBLE_R("AGC_HYSTERESIS", LAGC_CNTL_R2, RAGC_CNTL_R2, 6, 3, 0),
- SOC_DOUBLE_R("AGC_NOISE_THRESHOLD", LAGC_CNTL_R2,
- RAGC_CNTL_R2, 1, 31, 1),
+ SOC_DOUBLE_R("BEEP_VOL_CNTL", AIC3262_BEEP_CNTL_R1,
+ AIC3262_BEEP_CNTL_R2, 0, 0x0F, 1),
- SOC_DOUBLE_R("AGC_MAX_GAIN", LAGC_CNTL_R3, RAGC_CNTL_R3, 0, 116, 0),
- SOC_DOUBLE_R("AGC_ATCK_TIME", LAGC_CNTL_R4, RAGC_CNTL_R4, 3, 31, 0),
- SOC_DOUBLE_R("AGC_ATCK_SCALE_FACTOR",
- LAGC_CNTL_R4, RAGC_CNTL_R4, 0, 7, 0),
+ SOC_SINGLE("BEEP_MAS_VOL", AIC3262_BEEP_CNTL_R2, 6, 3, 0),
- SOC_DOUBLE_R("AGC_DECAY_TIME", LAGC_CNTL_R5, RAGC_CNTL_R5, 3, 31, 0),
- SOC_DOUBLE_R("AGC_DECAY_SCALE_FACTOR",
- LAGC_CNTL_R5, RAGC_CNTL_R5, 0, 7, 0),
- SOC_DOUBLE_R("AGC_NOISE_DEB_TIME", LAGC_CNTL_R6,
- RAGC_CNTL_R6, 0, 31, 0),
+ SOC_SINGLE("DAC PRB Selection", AIC3262_DAC_PRB, 0, 26, 0),
- SOC_DOUBLE_R("AGC_SGL_DEB_TIME", LAGC_CNTL_R7,
- RAGC_CNTL_R7, 0, 0x0F, 0),
+ SOC_SINGLE("ADC PRB Selection", AIC3262_ADC_PRB, 0, 18, 0),
- SOC_SINGLE("DAC PRB Selection",DAC_PRB, 0, 25, 0),
- SOC_SINGLE("HP_DEPOP", HP_DEPOP, 0, 255,0),
- SOC_DOUBLE("IN1 LO BYPASS VOLUME" , LINE_AMP_CNTL_R2, 3, 0, 3, 1),
SOC_ENUM("Input CM mode", input_cm_mode),
- SOC_ENUM("Output CM mode", output_cm_mode),
-};
-
-/* the sturcture contains the different values for mclk */
-static const struct aic3262_rate_divs aic3262_divs[] = {
-/*
- * mclk, rate, p_val, pll_j, pll_d, dosr, ndac, mdac, aosr, nadc, madc, blck_N,
- * codec_speficic_initializations
- */
- /* 8k rate */
-#ifdef CONFIG_MINI_DSP
- {12000000, 8000, 1, 8, 1920, 768, 8, 2, 128, 8, 12, 4,
- {{0, 60, 0}, {0, 61, 0} } },
-#else
- {12000000, 8000, 1, 8, 1920, 128, 12, 8, 128, 8, 6, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 8000, 1, 1, 3333, 128, 12, 8, 128, 8, 6, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 8000, 1, 4, 96, 128, 12, 8, 128, 12, 8, 4,
- {{0, 60, 1}, {0, 61, 1} } },
-#endif
- /* 11.025k rate */
- {12000000, 11025, 1, 1, 8816, 1024, 8, 2, 128, 8, 2, 48,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 11025, 1, 1, 8375, 1024, 8, 2, 128, 8, 2, 48,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 11025, 1, 3, 7632, 128, 8, 8, 128, 8, 8, 4,
- {{0, 60, 1}, {0, 61, 1} } },
-
- /* 16k rate */
-#ifdef CONFIG_MINI_DSP
- {12000000, 16000, 1, 8, 1920, 384, 4, 4, 128, 4, 12, 12,
- {{0, 60, 0}, {0, 61, 0} } },
- {12288000, 16000, 1, 9, 0, 216, 2, 16, 72, 2, 48, 27,
- {{0, 60, 0}, {0, 61, 0} } },
-#else
- {12000000, 16000, 1, 8, 1920, 128, 8, 6, 128, 8, 6, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 16000, 1, 2, 6667, 128, 8, 6, 128, 8, 6, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 16000, 1, 4, 96, 128, 8, 6, 128, 8, 6, 4,
- {{0, 60, 1}, {0, 61, 1} } },
-#endif
- /* 22.05k rate */
- {12000000, 22050, 1, 3, 7632, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 22050, 1, 3, 675, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 22050, 1, 3, 7632, 128, 8, 3, 128, 8, 3, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- /* 32k rate */
- {12000000, 32000, 1, 5, 4613, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 32000, 1, 5, 3333, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 32000, 1, 4, 96, 128, 6, 4, 128, 6, 4, 4,
- {{0, 60, 1}, {0, 61, 1} } },
-
-#ifdef CONFIG_MINI_DSP
- {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4,
- {{0, 60, 0}, {0, 61, 0} } },
- {12288000, 44100, 1, 7, 3548, 128, 2, 8, 128, 8, 2, 4,
- {{0, 60, 0}, {0, 61, 0} } },
-#else
- /* 44.1k rate */
- {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 44100, 1, 7, 3548, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 44100, 1, 3, 7632, 128, 4, 4, 64, 4, 4, 4,
- {{0, 60, 1}, {0, 61, 1} } },
-#endif
-
-#ifdef CONFIG_MINI_DSP
- {12288000, 48000, 1, 8, 52, 128, 2, 8, 128, 2, 8, 4,
- {{0, 60, 0}, {0, 61, 0} } },
- {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4,
- {{0, 60, 0}, {0, 61, 0}}},
-#else
- /* 48k rate */
- {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {12288000, 48000, 1, 8, 52, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 1}, {0, 61, 1} } },
- {24000000, 48000, 1, 4, 960, 128, 4, 4, 128, 4, 4, 4,
- {{0, 60, 1}, {0, 61, 1} } },
-#endif
+ SOC_ENUM("Output CM mode", output_cm_mode),
- /*96k rate */
- {12000000, 96000, 1, 16, 3840, 128, 8, 2, 128, 8, 2 , 4,
- {{0, 60, 7}, {0, 61, 7} } },
- {24000000, 96000, 1, 4, 960, 128, 4, 2, 128, 4, 2, 2,
- {{0, 60, 7}, {0, 61, 7} } },
- /*192k */
- {12000000, 192000, 1, 32, 7680, 128, 8, 2, 128, 8, 2, 4,
- {{0, 60, 17}, {0, 61, 13} } },
- {24000000, 192000, 1, 4, 960, 128, 2, 2, 128, 2, 2, 4,
- {{0, 60, 17}, {0, 61, 13} } },
+ SOC_SINGLE_EXT("FIRMWARE SET MODE", SND_SOC_NOPM, 0, 0xffff, 0,
+ aic3262_set_mode_get, aic3262_set_mode_put),
};
-
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_dump_regs
-* Purpose : This function is to mute or unmute the left and right DAC
-*
-*----------------------------------------------------------------------------
-*/
-static void aic3262_multi_i2s_dump_regs(struct snd_soc_dai *dai)
-{
- struct snd_soc_codec *codec = dai->codec;
- unsigned int counter;
-
- DBG(KERN_INFO "#%s: Dai Active %d ASI%d REGS DUMP\n",
- __func__, aic3262->active_count, dai->id);
-
- aic3262_change_page(codec, 0);
- aic3262_change_book(codec, 0);
-
- DBG(KERN_INFO "#Page0 REGS..\n");
- for (counter = 0; counter < 85; counter++) {
- DBG(KERN_INFO "#%2d -> 0x%x\n", counter,
- snd_soc_read(codec, counter));
- }
-
- DBG(KERN_INFO "#Page1 REGS..\n");
- for (counter = 128; counter < 176; counter++) {
- DBG(KERN_INFO "#%2d -> 0x%x\n", (counter % 128),
- snd_soc_read(codec, counter));
- }
-
- DBG(KERN_INFO "#Page4 REGS..\n");
- for (counter = 512; counter < 631; counter++) {
- DBG(KERN_INFO "#%2d -> 0x%x\n",
- (counter % 128), snd_soc_read(codec, counter));
- }
-
- for (counter = 0; counter < MAX_ASI_COUNT; counter++) {
- DBG(KERN_INFO "#ASI%d Frame %s @ %dHz Playback %d Record %d\n",
- (counter + 1),
- (aic3262->asiCtxt[counter].master == 1) ? "Master" : "Slave",
- aic3262->asiCtxt[counter].sampling_rate,
- aic3262->asiCtxt[counter].playback_mode,
- aic3262->asiCtxt[counter].capture_mode);
- DBG(KERN_INFO "#DAC Option [%d,%d] ADC Option %d WLEN %d\n\n",
- aic3262->asiCtxt[counter].left_dac_output,
- aic3262->asiCtxt[counter].right_dac_output,
- aic3262->asiCtxt[counter].adc_input,
- aic3262->asiCtxt[counter].word_len);
- }
- return;
-}
-
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_multi_i2s_mute
- * Purpose : This function is to mute or unmute the left and right DAC
- *
- *----------------------------------------------------------------------------
- */
-static int aic3262_multi_i2s_mute(struct snd_soc_dai *dai, int mute)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "#%s : mute entered with %d\n", __func__, mute);
-
- /* If we are doing both Recording and Playback on this DAI interface,
- * do not MUTE the Codec.
- */
- if (mute && (aic3262->asiCtxt[dai->id - 1].asi_active > 1)) {
- DBG("#%s Cannot Mute the ASI%d Now..\n",
- __func__, dai->id);
- } else {
- switch (dai->id) {
- case 1:
- aic3262_multi_i2s_asi1_mute(dai, mute);
- break;
- case 2:
- aic3262_multi_i2s_asi2_mute(dai, mute);
- break;
- case 3:
- aic3262_multi_i2s_asi3_mute(dai, mute);
- break;
- default:
- printk(KERN_ERR "#%s: Invalid DAI id\n", __func__);
- return -EINVAL;
- }
- }
- DBG(KERN_INFO "#%s : mute ended\n", __func__);
- return 0;
-}
-
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_asi1_mute
-* Purpose : This function is to mute or unmute the left and right DAC
-*
-*----------------------------------------------------------------------------
-*/
-static int aic3262_multi_i2s_asi1_mute(struct snd_soc_dai *dai, int mute)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute);
-
- if (mute && !aic3262->asiCtxt[0].port_muted ) {
- DBG(KERN_INFO "Mute if part\n");
-
-
- snd_soc_update_bits(codec, DAC_MVOL_CONF, DAC_LR_MUTE_MASK,DAC_LR_MUTE);
-
- /* First check if both Playback and Recording is going on
- * this interface.
- */
- if (aic3262->asiCtxt[0].asi_active > 1) {
- DBG("#%s Cannot Mute the ASI Now..\n", __func__);
- } else if (!(aic3262->asiCtxt[1].playback_mode) &&
- !(aic3262->asiCtxt[2].playback_mode)) {
- /* Before Muting, please check if any other
- * ASI is active. if so, we cannot simply mute the
- * DAC and ADC Registers.
- */
- DBG("#%s None of the ASI's are active now..\n", __func__);
- snd_soc_write(codec, DAC_MVOL_CONF,
- ((aic3262->dac_reg & 0xF3) | 0x0C));
- snd_soc_write(codec, ADC_FINE_GAIN,
- ((aic3262->adc_gain & 0x77) | 0x88));
- snd_soc_write(codec, HPL_VOL, 0xB9);
- snd_soc_write(codec, HPR_VOL, 0xB9);
- snd_soc_write(codec, REC_AMP_CNTL_R5, 0x39);
- snd_soc_write(codec, RAMPR_VOL, 0x39);
- snd_soc_write(codec, SPK_AMP_CNTL_R4, 0x00);
- aic3262->asiCtxt[0].port_muted = 1;
- }
- } else {
- DBG(KERN_INFO "Mute else part\n");
- snd_soc_update_bits(codec, DAC_MVOL_CONF,
- DAC_LR_MUTE_MASK, 0x0);
- snd_soc_write(codec, ADC_FINE_GAIN,(0X00 & 0x77) | 0x0);
- aic3262_multi_i2s_dump_regs(dai);
- }
-
- DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute);
-
- return 0;
-}
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_asi2_maic3262_asi3_clk_configute
-* Purpose : This function is to mute or unmute the left and right DAC
-*
-*----------------------------------------------------------------------------
-*/
-static int aic3262_multi_i2s_asi2_mute(struct snd_soc_dai *dai, int mute)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute);
-
- if (mute && !aic3262->asiCtxt[1].port_muted ) {
- DBG(KERN_INFO "Mute if part\n");
- snd_soc_update_bits(codec, DAC_MVOL_CONF, DAC_LR_MUTE_MASK,DAC_LR_MUTE);
-
- /* First check if both Playback and Recording is going on
- * this interface.
- */
- if (aic3262->asiCtxt[1].asi_active > 1) {
- DBG("#%s Cannot Mute the ASI Now..\n", __func__);
- } else if (!(aic3262->asiCtxt[0].playback_mode) &&
- !(aic3262->asiCtxt[2].playback_mode)) {
- /* Before Muting, please check if any other
- * ASI is active. if so, we cannot simply mute the
- * DAC and ADC Registers.
- */
- snd_soc_write(codec, DAC_MVOL_CONF,
- ((aic3262->dac_reg & 0xF3) | 0x0C));
- snd_soc_write(codec, ADC_FINE_GAIN,
- ((aic3262->adc_gain & 0x77) | 0x88));
- snd_soc_write(codec, HPL_VOL, 0xB9);
- snd_soc_write(codec, HPR_VOL, 0xB9);
- snd_soc_write(codec, REC_AMP_CNTL_R5, 0x39);
- snd_soc_write(codec, RAMPR_VOL, 0x39);
- snd_soc_write(codec, SPK_AMP_CNTL_R4, 0x00);
- aic3262->asiCtxt[1].port_muted = 1;
- }
- } else {
- DBG(KERN_INFO "Mute else part\n");
- snd_soc_update_bits(codec, DAC_MVOL_CONF,
- DAC_LR_MUTE_MASK, 0x0);
-
- /*aic3262_multi_i2s_dump_regs(dai);*/
- }
-
- DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute);
-
- return 0;
-}
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_asi3_mute
-* Purpose : This function is to mute or unmute the left and right DAC
-*
-*----------------------------------------------------------------------------
-*/
-static int aic3262_multi_i2s_asi3_mute(struct snd_soc_dai *dai, int mute)
-{
- struct snd_soc_codec *codec = dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "#%s : mute %d started\n", __func__, mute);
-
- if (mute && !aic3262->asiCtxt[2].port_muted) {
- DBG("Mute if part\n");
- snd_soc_update_bits(codec, DAC_MVOL_CONF, DAC_LR_MUTE_MASK,DAC_LR_MUTE);
-
- /* First check if both Playback and Recording is going on
- * this interface.
- */
- if (aic3262->asiCtxt[2].asi_active > 1) {
- DBG("#%s Cannot Mute the ASI Now..\n", __func__);
- } else if (!(aic3262->asiCtxt[0].playback_mode) &&
- !(aic3262->asiCtxt[1].playback_mode)) {
- /* Before Muting, please check if any other
- * ASI is active. if so, we cannot simply mute the
- * DAC and ADC Registers.
- */
- snd_soc_write(codec, DAC_MVOL_CONF,
- ((aic3262->dac_reg & 0xF3) | 0x0C));
- snd_soc_write(codec, ADC_FINE_GAIN,
- ((aic3262->adc_gain & 0x77) | 0x88));
- snd_soc_write(codec, HPL_VOL, 0xB9);
- snd_soc_write(codec, HPR_VOL, 0xB9);
- snd_soc_write(codec, REC_AMP_CNTL_R5, 0x39);
- snd_soc_write(codec, RAMPR_VOL, 0x39);
- snd_soc_write(codec, SPK_AMP_CNTL_R4, 0x00);
- aic3262->asiCtxt[2].port_muted = 1;
- }
- } else {
- DBG("Mute else part\n");
- snd_soc_update_bits(codec, DAC_MVOL_CONF,
- DAC_LR_MUTE_MASK, 0x0);
-
- /*aic3262_multi_i2s_dump_regs(dai);*/
-
- }
-
- DBG(KERN_INFO "#%s : mute %d ended\n", __func__, mute);
-
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_multi_i2s_set_dai_fmt
- * Purpose : This function is to set the DAI format
- *
- *----------------------------------------------------------------------------
- */
-static int aic3262_multi_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
-{
- /* Check the DAI Id and based on that switch the configuration for
- * the Individual ASI Port.
- */
- switch (codec_dai->id) {
- case 1:
- aic3262_multi_i2s_asi1_set_dai_fmt(codec_dai, fmt);
- break;
- case 2:
- aic3262_multi_i2s_asi2_set_dai_fmt(codec_dai, fmt);
- break;
- case 3:
- aic3262_multi_i2s_asi3_set_dai_fmt(codec_dai, fmt);
- break;
- default:
- printk(KERN_ERR
- "#%s: Invalid DAI interface format\n", __func__);
- return -EINVAL;
- }
- return 0;
-}
-
-
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_asi1_set_dai_fmt
-* Purpose : This function is to set the DAI format for ASI1 Port
-*
-*----------------------------------------------------------------------------
-*/
-static int aic3262_multi_i2s_asi1_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 iface_reg, clk_reg;
- u8 regvalue;
-
- DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n",
- __func__, codec_dai->id, fmt);
-
- /* Read the B0_P4_R4 and B0_P4_R10 Registers to configure the
- * ASI1 Bus and Clock Formats depending on the PCM Format.
- */
- iface_reg = snd_soc_read(codec, ASI1_BUS_FMT);
- clk_reg = snd_soc_read(codec, ASI1_BWCLK_CNTL_REG);
-
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n",
- __func__, codec_dai->id);
- aic3262->asiCtxt[0].master = 1;
- clk_reg |= (BIT5 | BIT2); /* Codec Interface as Master */
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n",
- __func__, codec_dai->id);
- clk_reg &= ~0xFC; /* Reset bits D[7:5] and D[4:2] to zero */
- aic3262->asiCtxt[0].master = 0;
- break;
- case SND_SOC_DAIFMT_CBS_CFM:
- /* new case..just for debugging */
- DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__);
- aic3262->asiCtxt[0].master = 0;
- clk_reg |= BIT5; /* Only WCLK1 Output from Codec */
- clk_reg &= ~0x1C; /* BCLK1 Input to Codec */
- break;
- default:
- printk(KERN_ERR "#%s: Invalid DAI master/slave interface\n",
- __func__);
- return -EINVAL;
- }
- aic3262->asiCtxt[0].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
- /* interface format */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- DBG(KERN_INFO "#%s: Configuring ASI%d for I2s Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f);
- break;
- case SND_SOC_DAIFMT_DSP_A:
- DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f) | 0x20;
- break;
- case SND_SOC_DAIFMT_RIGHT_J:
- iface_reg = (iface_reg & 0x1f) | 0x40;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- iface_reg = (iface_reg & 0x1f) | 0x60;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_B Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f) | 0x80;
- /* voice call need data offset in 1 bitclock */
- snd_soc_write(codec, ASI1_LCH_OFFSET, 1);
- break;
- default:
- printk(KERN_ERR
- "#%s: Invalid DAI interface format\n", __func__);
- return -EINVAL;
- }
- /* Also Configure the Pin Control Registers before writing into
- * the ASI specific Clock Control and Format Registers
- */
-
- /* Configure B0_P4_R65_D[5:2] to 001 This configures the
- * WCLK1 Pin to ASI1
- */
- regvalue = snd_soc_read(codec, WCLK1_PIN_CNTL_REG);
- snd_soc_write(codec, WCLK1_PIN_CNTL_REG, (regvalue | BIT2));
-
- /* Configure B0_P4_R68_d[6:5] = 01 and B0_P4_R67_D[4:1] to 0001
- * to ensure that the DIN1 and DOUT1 Pins are configured
- * correctly
- */
- regvalue = snd_soc_read(codec, DIN1_PIN_CNTL_REG);
- snd_soc_write(codec, DIN1_PIN_CNTL_REG, (regvalue | BIT5));
- regvalue = snd_soc_read(codec, DOUT1_PIN_CNTL_REG);
- snd_soc_write(codec, DOUT1_PIN_CNTL_REG, (regvalue | BIT1));
-
- snd_soc_write(codec, ASI1_BWCLK_CNTL_REG, clk_reg);
-
- snd_soc_write(codec, ASI1_BUS_FMT, iface_reg);
-
- return 0;
-}
-
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_asi2_set_dai_fmt
-* Purpose : This function is to set the DAI format for ASI2 Port
-*
-*----------------------------------------------------------------------------
-*/
-static int aic3262_multi_i2s_asi2_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 iface_reg, clk_reg;
- u8 regvalue;
-
- DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n",
- __func__, codec_dai->id, fmt);
-
- /* Read the B0_P4_R17 and B0_P4_R26 Registers to configure the
- * ASI1 Bus and Clock Formats depending on the PCM Format.
- */
- iface_reg = snd_soc_read(codec, ASI2_BUS_FMT);
- clk_reg = snd_soc_read(codec, ASI2_BWCLK_CNTL_REG);
-
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n",
- __func__, codec_dai->id);
- aic3262->asiCtxt[1].master = 1;
- clk_reg |= (BIT5 | BIT2);
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n",
- __func__, codec_dai->id);
-
- clk_reg &= ~0xFC;
- aic3262->asiCtxt[1].master = 0;
- break;
- case SND_SOC_DAIFMT_CBS_CFM:
- /*new case..just for debugging */
- DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__);
- aic3262->asiCtxt[1].master = 0;
- clk_reg |= BIT5;
- clk_reg &= ~0x1C;
- break;
- default:
- printk(KERN_ERR "#%s:Invalid DAI master/slave interface\n",
- __func__);
- return -EINVAL;
- }
- aic3262->asiCtxt[1].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
- /* interface format */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- DBG(KERN_INFO "#%s: Configuring ASI%d for I2S Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f);
- break;
- case SND_SOC_DAIFMT_DSP_A:
- DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f) | 0x20;
- break;
- case SND_SOC_DAIFMT_RIGHT_J:
- iface_reg = (iface_reg & 0x1f) | 0x40;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- iface_reg = (iface_reg & 0x1f) | 0x60;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- DBG(KERN_INFO "#%s: Configuring ASI%d for DSP Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f) | 0x80;
- /* voice call need data offset in 1 bitclock */
- snd_soc_write(codec, ASI2_LCH_OFFSET, 1);
- break;
- default:
- printk(KERN_ERR "#%s:Invalid DAI interface format\n", __func__);
- return -EINVAL;
- }
-
- /* Also Configure the Pin Control Registers before writing into
- * the ASI2 specific Clock Control and Format Registers
- */
-
- /* Configure B0_P4_R69_D[5:2] to 001 This configures the
- * WCLK2 Pin to ASI2
- */
-
- regvalue = snd_soc_read(codec, WCLK2_PIN_CNTL_REG);
- snd_soc_write(codec, WCLK2_PIN_CNTL_REG, (regvalue | BIT2));
-
- regvalue = snd_soc_read(codec, BCLK2_PIN_CNTL_REG);
- snd_soc_write(codec, BCLK2_PIN_CNTL_REG, (regvalue | BIT2));
-
- /* Configure B0_P4_R72_d[6:5] = 01 and B0_P4_R71_D[4:1] to 0001
- * to ensure that the DIN2 and DOUT2 Pins are configured
- * correctly
- */
- regvalue = snd_soc_read(codec, DIN2_PIN_CNTL_REG);
- snd_soc_write(codec, DIN2_PIN_CNTL_REG, (regvalue | BIT5));
-
- regvalue = snd_soc_read(codec, DOUT2_PIN_CNTL_REG);
- snd_soc_write(codec, DOUT2_PIN_CNTL_REG, (regvalue | BIT5 | BIT1));
-
- snd_soc_write(codec, ASI2_BWCLK_CNTL_REG, clk_reg);
-
- snd_soc_write(codec, ASI2_BUS_FMT, iface_reg);
-
- return 0;
-}
-
-/*
-*----------------------------------------------------------------------------
-* Function : aic3262_multi_i2s_asi3_set_dai_fmt
-* Purpose : This function is to set the DAI format for ASI3 Port
-*
-*----------------------------------------------------------------------------
-*/
-static int aic3262_multi_i2s_asi3_set_dai_fmt(struct snd_soc_dai *codec_dai,
- unsigned int fmt)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 iface_reg, clk_reg;
- u8 regvalue;
-
- DBG(KERN_INFO "%s: DAI_ID %d fmt %d\n",
- __func__, codec_dai->id, fmt);
-
- /* Read the B0_P4_R33 and B0_P4_R42 Registers to configure the
- * ASI1 Bus and Clock Formats depending on the PCM Format.
- */
- iface_reg = snd_soc_read(codec, ASI3_BUS_FMT);
- clk_reg = snd_soc_read(codec, ASI3_BWCLK_CNTL_REG);
-
- /* set master/slave audio interface */
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBM_CFM:
- DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Master..\n",
- __func__, codec_dai->id);
- aic3262->asiCtxt[2].master = 1;
- clk_reg |= (BIT5 | BIT2);
- break;
- case SND_SOC_DAIFMT_CBS_CFS:
- DBG(KERN_INFO "#%s: Configuring ASI%d as Frame Slave..\n",
- __func__, codec_dai->id);
- clk_reg &= ~0xFC;
- aic3262->asiCtxt[2].master = 0;
- break;
- case SND_SOC_DAIFMT_CBS_CFM:
- /* new case..just for debugging */
- DBG(KERN_INFO "%s: SND_SOC_DAIFMT_CBS_CFM\n", __func__);
- aic3262->asiCtxt[2].master = 0;
- clk_reg |= BIT5;
- clk_reg &= ~0x1C;
- break;
- default:
- printk(KERN_ERR "Invalid DAI master/slave interface\n");
- return -EINVAL;
- }
- aic3262->asiCtxt[2].pcm_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK);
- /* interface format */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- DBG(KERN_INFO "#%s: Configuring ASI%d for I2S Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f);
- break;
- case SND_SOC_DAIFMT_DSP_A:
- DBG(KERN_INFO "#%s: Configuring ASI%d for DSP_A Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f) | 0x20;
- break;
- case SND_SOC_DAIFMT_RIGHT_J:
- iface_reg = (iface_reg & 0x1f) | 0x40;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- iface_reg = (iface_reg & 0x1f) | 0x60;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- DBG(KERN_INFO "#%s: Configuring ASI%d for DSP Mode..\n",
- __func__, codec_dai->id);
- iface_reg = (iface_reg & 0x1f) | 0x80;
- /* voice call need data offset in 1 bitclock */
- snd_soc_write(codec, ASI3_LCH_OFFSET, 1);
- break;
- default:
- printk(KERN_ERR
- "#%s: Invalid DAI interface format\n", __func__);
- return -EINVAL;
- }
-
- /* Also Configure the Pin Control Registers before writing into
- * the ASI specific Clock Control and Format Registers
- */
- /* Configure B0_P4_R73_D[5:2] to 0001 This configures the
- * WCLK1 Pin to ASI1
- */
- regvalue = snd_soc_read(codec, WCLK3_PIN_CNTL_REG);
- snd_soc_write(codec, WCLK3_PIN_CNTL_REG, (regvalue | BIT2));
-
- regvalue = snd_soc_read(codec, BCLK3_PIN_CNTL_REG);
- snd_soc_write(codec, BCLK3_PIN_CNTL_REG, (regvalue | BIT2));
-
- /* Configure B0_P4_R76_d[6:5] = 01 and B0_P4_R75_D[4:1] to 0001
- * to ensure that the DIN1 and DOUT1 Pins are configured
- * correctly
- */
- regvalue = snd_soc_read(codec, DIN3_PIN_CNTL_REG);
- snd_soc_write(codec, DIN3_PIN_CNTL_REG, (regvalue | BIT5));
- regvalue = snd_soc_read(codec, DOUT3_PIN_CNTL_REG);
- snd_soc_write(codec, DOUT3_PIN_CNTL_REG, (regvalue | BIT1));
-
- snd_soc_write(codec, ASI3_BWCLK_CNTL_REG, clk_reg);
-
- snd_soc_write(codec, ASI3_BUS_FMT, iface_reg);
-
- return 0;
-}
-
-/*
- * Clock after PLL and dividers
- */
-static int aic3262_multi_i2s_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "#%s: DAI ID %d Freq %d Direction %d\n",
- __func__, codec_dai->id, freq, dir);
- switch (freq) {
- case AIC3262_FREQ_12000000:
- case AIC3262_FREQ_12288000:
- case AIC3262_FREQ_24000000:
- aic3262->sysclk = freq;
- return 0;
- break;
- }
- printk(KERN_ERR "Invalid frequency to set DAI system clock\n");
- return -EINVAL;
-}
-
-/*
-* aic3262_multi_i2s_set_pll
-*
-* This function is invoked as part of the PLL call-back
-* handler from the ALSA layer.
-*/
-static int aic3262_multi_i2s_set_dai_pll(struct snd_soc_dai *codec_dai,
- int pll_id, int source, unsigned int freq_in,
- unsigned int freq_out)
-{
-
- printk(KERN_INFO "%s: DAI ID %d PLL_ID %d InFreq %d OutFreq %d\n",
- __func__, pll_id, codec_dai->id, freq_in, freq_out);
-
- return 0;
-}
-
-/*
-* aic3262_asi1_clk_config
-*
-* This function is used to configure the BCLK1, WCLK1 pins which
-* are specific to ASI1 Interface. This function just enables the
-* BCLk and WCLK along with the miniDSP Port Control Registers.
-* However, depending on the user requirement, this function can also be
-* extended to configure the sourc for the BCLK and WCLK on a ASI basis.
-*/
-static int aic3262_asi1_clk_config(struct snd_soc_codec *codec,
- struct snd_pcm_hw_params *params)
-{
- u8 bclk_N_value, wclk_N_value;
- u8 minidspD_data, minidspA_data;
- u8 regval;
-
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "%s: Invoked\n", __func__);
-
- /* Configure the BCLK and WCLK Output Mux Options */
- regval = snd_soc_read(codec, ASI1_BWCLK_OUT_CNTL);
- regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK);
-
- regval |= (aic3262->asiCtxt[0].bclk_output <<
- AIC3262_ASI_BCLK_MUX_SHIFT);
- regval |= aic3262->asiCtxt[0].wclk_output;
- snd_soc_write(codec, ASI1_BWCLK_OUT_CNTL, regval);
-
- /* Configure the corresponding miniDSP Data Ports */
- minidspD_data = snd_soc_read(codec, MINIDSP_PORT_CNTL_REG);
- minidspD_data &= ~(BIT5 | BIT4);
- snd_soc_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data);
-
- minidspA_data = snd_soc_read(codec, ASI1_ADC_INPUT_CNTL);
- minidspA_data &= ~(BIT2 | BIT1 | BIT0);
- minidspA_data |= aic3262->asiCtxt[0].adc_input;
- snd_soc_write(codec, ASI1_ADC_INPUT_CNTL, minidspA_data);
-
-
- if (aic3262->asiCtxt[0].master == 1) {
- DBG(KERN_INFO
- "#%s: Codec Master on ASI1 Port. Enabling BCLK WCLK Divider.\n",
- __func__);
- bclk_N_value = aic3262->asiCtxt[0].bclk_div;
- snd_soc_write(codec, ASI1_BCLK_N, (bclk_N_value | 0x80));
-
- wclk_N_value = snd_soc_read(codec, ASI1_WCLK_N);
- snd_soc_write(codec, ASI1_WCLK_N, (wclk_N_value | 0xA0));
- }
- return 0;
-
-}
-
-/*
-* aic3262_asi2_clk_config
-*
-* This function is used to configure the BCLK2, WCLK2 pins which
-* are specific to ASI2 Interface. This function just enables the
-* BCLk and WCLK along with the miniDSP Port Control Registers.
-* However, depending on the user requirement, this function can also be
-* extended to configure the sourc for the BCLK and WCLK on a ASI basis.
-*/
-static int aic3262_asi2_clk_config(struct snd_soc_codec *codec,
- struct snd_pcm_hw_params *params)
-{
- u8 bclk_N_value, wclk_N_value, minidspD_data, minidspA_data;
- u8 regval;
-
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "%s: Invoked\n", __func__);
-
-
- /* Configure the BCLK and WCLK Output Mux Options */
- regval = snd_soc_read(codec, ASI2_BWCLK_OUT_CNTL);
- regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK);
- regval |= (aic3262->asiCtxt[1].bclk_output <<
- AIC3262_ASI_BCLK_MUX_SHIFT);
- regval |= aic3262->asiCtxt[1].wclk_output;
-
- snd_soc_write(codec, ASI2_BWCLK_OUT_CNTL, regval);
- /* Configure the corresponding miniDSP Data Ports */
- minidspD_data = snd_soc_read(codec, MINIDSP_PORT_CNTL_REG);
- minidspD_data |= (BIT2);
- snd_soc_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data);
-
- minidspA_data = snd_soc_read(codec, ASI2_ADC_INPUT_CNTL);
- minidspA_data &= ~(BIT2 | BIT1 | BIT0);
- minidspA_data |= aic3262->asiCtxt[1].adc_input;
- snd_soc_write(codec, ASI2_ADC_INPUT_CNTL, minidspA_data);
-
- /* NO Manual configuration of WCLK and BCLK for Master Mode.
- * DAPM Handles all the required modifications.
- */
- if (aic3262->asiCtxt[1].master == 1) {
- DBG(KERN_INFO
- "#%s: Codec Master on ASI2 Port. Enabling BCLK WCLK Divider.\n",
- __func__);
- bclk_N_value = aic3262->asiCtxt[1].bclk_div;
- snd_soc_write(codec, ASI2_BCLK_N, (bclk_N_value | 0x80));
-
- wclk_N_value = snd_soc_read(codec, ASI2_WCLK_N);
- snd_soc_write(codec, ASI2_WCLK_N, (wclk_N_value | 0xA0));
- }
-
- return 0;
-
-}
-
-/*
-* aic3262_asi3_clk_config
-*
-* This function is used to configure the BCLK3, WCLK3 pins which
-* are specific to ASI3 Interface. This function just enables the
-* BCLk and WCLK along with the miniDSP Port Control Registers.
-* However, depending on the user requirement, this function can also be
-* extended to configure the sourc for the BCLK and WCLK on a ASI basis.
-*/
-static int aic3262_asi3_clk_config(struct snd_soc_codec *codec,
- struct snd_pcm_hw_params *params)
-{
- u8 bclk_N_value, wclk_N_value, minidspD_data, minidspA_data;
- u8 regval;
-
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "%s:\n", __func__);
-
-
- /* Configure the BCLK and WCLK Output Mux Options */
- regval = snd_soc_read(codec, ASI3_BWCLK_OUT_CNTL);
- regval &= ~(AIC3262_ASI_BCLK_MUX_MASK | AIC3262_ASI_WCLK_MUX_MASK);
- regval |= (aic3262->asiCtxt[2].bclk_output <<
- AIC3262_ASI_BCLK_MUX_SHIFT);
- regval |= aic3262->asiCtxt[2].wclk_output;
- snd_soc_write(codec, ASI3_BWCLK_OUT_CNTL, regval);
-
- minidspD_data = snd_soc_read(codec, MINIDSP_PORT_CNTL_REG);
- minidspD_data |= (BIT1);
- snd_soc_write(codec, MINIDSP_PORT_CNTL_REG, minidspD_data);
-
- minidspA_data = snd_soc_read(codec, ASI3_ADC_INPUT_CNTL);
- minidspA_data &= ~(BIT2 | BIT1 | BIT0);
- minidspA_data |= aic3262->asiCtxt[2].adc_input;
- snd_soc_write(codec, ASI3_ADC_INPUT_CNTL, minidspA_data);
-
- if (aic3262->asiCtxt[2].master == 1) {
- DBG(KERN_INFO
- "#%s: Codec Master on ASI3 Port. Enabling BCLK WCLK Divider.\n",
- __func__);
- bclk_N_value = aic3262->asiCtxt[2].bclk_div;
- snd_soc_write(codec, ASI2_BCLK_N, (bclk_N_value | 0x80));
-
- wclk_N_value = snd_soc_read(codec, ASI3_WCLK_N);
- snd_soc_write(codec, ASI3_WCLK_N, (wclk_N_value | 0xA0));
- }
- return 0;
-
-}
-
-/*
-* aic3262_multi_i2s_hw_params
-*
-* This function is used to configure the individual ASI port registers
-* depending on the configuration passed on by the snd_pcm_hw_params
-* structure.
-* This function internally configures the ASI specific pins and clock
-* Control Registers.
-*/
-static int aic3262_multi_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- int i, j;
- u8 data;
- u16 regoffset = 0;
- u8 dacpath = 0;
- u8 adcpath = 0;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- DBG(KERN_INFO "#%s: Invoked for ASI%d Port for %s Mode\n",
- __func__, dai->id,
- (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- ? "Playback" : "Record");
-
- i = aic3262_get_divs(aic3262->sysclk, params_rate(params));
-
- i2c_verify_book0(codec);
-
- if (i < 0) {
- printk(KERN_ERR "#%s: Sampling rate %d not supported\n",
- __func__, params_rate(params));
- return i;
- }
-
- aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* Configure the PLL J, R D values only if none of the ASI
- * Interfaces are Active.
- */
-
- if (1) {
- DBG(KERN_INFO "#%s: None of the ASIs active yet...\n",
- __func__);
- /*We will fix R value to 1 and make P & J=K.D as variable */
- /* Setting P & R values are set to 1 and 1 at init*/
-
- /* J value */
- snd_soc_write(codec, PLL_J_REG, aic3262_divs[i].pll_j);
-
- /* MSB & LSB for D value */
-
- snd_soc_write(codec, PLL_D_MSB, (aic3262_divs[i].pll_d >> 8));
- snd_soc_write(codec, PLL_D_LSB,
- (aic3262_divs[i].pll_d & AIC3262_8BITS_MASK));
-
- /* NDAC divider value */
- data = snd_soc_read(codec, NDAC_DIV_POW_REG);
- DBG(KERN_INFO "# reading NDAC = %d , NDAC_DIV_POW_REG = %x\n",
- aic3262_divs[i].ndac, data);
- snd_soc_write(codec, NDAC_DIV_POW_REG,
- ((data & 0x80)|(aic3262_divs[i].ndac)));
- DBG(KERN_INFO "# writing NDAC = %d , NDAC_DIV_POW_REG = %x\n",
- aic3262_divs[i].ndac,
- ((data & 0x80)|(aic3262_divs[i].ndac)));
-
- /* MDAC divider value */
- data = snd_soc_read(codec, MDAC_DIV_POW_REG);
- DBG(KERN_INFO "# reading MDAC = %d , MDAC_DIV_POW_REG = %x\n",
- aic3262_divs[i].mdac, data);
- snd_soc_write(codec, MDAC_DIV_POW_REG,
- ((data & 0x80)|(aic3262_divs[i].mdac)));
- DBG(KERN_INFO "# writing MDAC = %d , MDAC_DIV_POW_REG = %x\n",
- aic3262_divs[i].mdac, ((data & 0x80)|(aic3262_divs[i].mdac)));
-
- /* DOSR MSB & LSB values */
- snd_soc_write(codec, DOSR_MSB_REG, aic3262_divs[i].dosr >> 8);
- DBG(KERN_INFO "# writing DOSR_MSB_REG = %d\n",
- (aic3262_divs[i].dosr >> 8));
- snd_soc_write(codec, DOSR_LSB_REG,
- aic3262_divs[i].dosr & AIC3262_8BITS_MASK);
- DBG(KERN_INFO "# writing DOSR_LSB_REG = %d\n",
- (aic3262_divs[i].dosr & AIC3262_8BITS_MASK));
-
- /* NADC divider value */
- data = snd_soc_read(codec, NADC_DIV_POW_REG);
- snd_soc_write(codec, NADC_DIV_POW_REG,
- ((data & 0x80)|(aic3262_divs[i].nadc)));
- DBG(KERN_INFO "# writing NADC_DIV_POW_REG = %d\n",
- aic3262_divs[i].nadc);
-
- /* MADC divider value */
- data = snd_soc_read(codec, MADC_DIV_POW_REG);
- snd_soc_write(codec, MADC_DIV_POW_REG,
- ((data & 0x80)|(aic3262_divs[i].madc)));
- DBG(KERN_INFO "# writing MADC_DIV_POW_REG = %d\n",
- aic3262_divs[i].madc);
-
- /* AOSR value */
- snd_soc_write(codec, AOSR_REG, aic3262_divs[i].aosr);
- DBG(KERN_INFO "# writing AOSR = %d\n", aic3262_divs[i].aosr);
- } else {
- DBG(KERN_INFO "#Atleast 1 ASI Active. Cannot Program PLL..\n");
- }
- /* Check for the DAI ID to know which ASI needs
- * Configuration.
- */
- switch (dai->id) {
- case 1:
- regoffset = ASI1_BUS_FMT;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- DBG(KERN_INFO "#%s: ASI1 DAC Inputs enabled..\n",
- __func__);
- /* Read the DAC Control Register and configure it
- * as per the ASIContext Structure Settings.
- */
- dacpath = snd_soc_read(codec, ASI1_DAC_OUT_CNTL);
- dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK |
- AIC3262_ASI_RDAC_PATH_MASK);
- dacpath |= (aic3262->asiCtxt[0].left_dac_output
- << AIC3262_ASI_LDAC_PATH_SHIFT);
-
- dacpath |= (aic3262->asiCtxt[0].right_dac_output
- << AIC3262_ASI_RDAC_PATH_SHIFT);
- snd_soc_write(codec, ASI1_DAC_OUT_CNTL, dacpath);
-
- aic3262->asiCtxt[0].playback_mode = 1;
- aic3262->asiCtxt[0].bclk_div =
- aic3262_divs[i].blck_N;
- } else {
- /* For Recording, Configure the DOUT Pin as per
- * ASIContext Structure Settings.
- */
- adcpath = snd_soc_read(codec, ASI1_DATA_OUT);
- adcpath &= ~(AIC3262_ASI_DOUT_MASK);
-
- adcpath |= aic3262->asiCtxt[0].dout_option;
- snd_soc_write(codec, ASI1_DATA_OUT, adcpath);
-
- aic3262->asiCtxt[0].capture_mode = 1;
- }
- break;
- case 2:
- regoffset = ASI2_BUS_FMT;
-
- /* Since we are configuring ASI2, please check if Playback
- * is expected. If so, enable ASI2 Inputs to Left and
- * Right DACs
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- DBG(KERN_INFO "#%s: ASI2 DAC Inputs enabled..\n",
- __func__);
- /* Read the DAC Control Register and configure it
- * as per theASIContext Structure Settings.
- */
- dacpath = snd_soc_read(codec, ASI2_DAC_OUT_CNTL);
- dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK |
- AIC3262_ASI_RDAC_PATH_MASK);
- dacpath |= (aic3262->asiCtxt[1].left_dac_output
- << AIC3262_ASI_LDAC_PATH_SHIFT);
-
- dacpath |= (aic3262->asiCtxt[1].right_dac_output
- << AIC3262_ASI_RDAC_PATH_SHIFT);
- snd_soc_write(codec, ASI2_DAC_OUT_CNTL, dacpath);
- aic3262->asiCtxt[1].playback_mode = 1;
-
- aic3262->asiCtxt[1].bclk_div =
- aic3262_divs[i].blck_N;
- } else {
- /* For Recording, Configure the DOUT Pin as per
- * ASIContext Structure Settings.
- */
- adcpath = snd_soc_read(codec, ASI2_DATA_OUT);
- adcpath &= ~(AIC3262_ASI_DOUT_MASK);
- adcpath |= aic3262->asiCtxt[1].dout_option;
- snd_soc_write(codec, ASI2_DATA_OUT, adcpath);
-
- aic3262->asiCtxt[1].capture_mode = 1;
- }
- break;
- case 3:
- regoffset = ASI3_BUS_FMT;
- /* Since we are configuring ASI3, please check if Playback
- * is expected. If so, enable ASI3 Inputs to Left and
- * Right DACs
- */
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- DBG(KERN_INFO "#%s:ASI3 DAC Inputs enabled.\n",
- __func__);
- /* Read the DAC Control Register and configure
- * it as per the ASIContext Structure Settings.
- */
- dacpath = snd_soc_read(codec, ASI3_DAC_OUT_CNTL);
- dacpath &= ~(AIC3262_ASI_LDAC_PATH_MASK |
- AIC3262_ASI_RDAC_PATH_MASK);
- dacpath |= (aic3262->asiCtxt[2].left_dac_output
- << AIC3262_ASI_LDAC_PATH_SHIFT);
- dacpath |= (aic3262->asiCtxt[2].right_dac_output
- << AIC3262_ASI_RDAC_PATH_SHIFT);
- snd_soc_write(codec,
- ASI3_DAC_OUT_CNTL, dacpath);
-
- aic3262->asiCtxt[2].playback_mode = 1;
-
- aic3262->asiCtxt[2].bclk_div =
- aic3262_divs[i].blck_N;
- } else {
- /* For Recording, Configure the DOUT Pin as per
- * ASIContext Structure Settings.
- */
- adcpath &= ~(AIC3262_ASI_DOUT_MASK);
- adcpath |= aic3262->asiCtxt[2].dout_option;
- snd_soc_write(codec, ASI3_DATA_OUT, adcpath);
-
- aic3262->asiCtxt[2].capture_mode = 1;
- }
- break;
- default:
- printk(KERN_ERR "Invalid Dai ID %d in %s",
- dai->id, __func__);
- break;
- }
- DBG(KERN_INFO "#%s: Reading Pg %d Reg %d for Bus Format Control.\n",
- __func__, (regoffset/128), (regoffset % 128));
-
- /* Read the correspondig ASI DAI Interface Register */
- data = snd_soc_read(codec, regoffset);
-
- data = data & 0xe7;
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- DBG(KERN_INFO "#%s: Configuring ASI%d S16_LE Fmt..\n",
- __func__, dai->id);
- data = data | 0x00;
- aic3262->asiCtxt[dai->id - 1].word_len = 16;
- break;
- case SNDRV_PCM_FORMAT_S20_3LE:
- data |= (0x08);
- aic3262->asiCtxt[dai->id - 1].word_len = 20;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- DBG(KERN_INFO "#%s: Configuring ASI%d S24_LE Fmt..\n",
- __func__, dai->id);
- data |= (0x10);
- aic3262->asiCtxt[dai->id - 1].word_len = 24;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- DBG(KERN_INFO "#%s: Configuring ASI%d S32_LE Fmt..\n",
- __func__, dai->id);
- data |= (0x18);
- aic3262->asiCtxt[dai->id - 1].word_len = 32;
- break;
- }
-
- /* configure the respective Registers for the above configuration */
- snd_soc_write(codec, regoffset, data);
-
- for (j = 0; j < NO_FEATURE_REGS; j++) {
- snd_soc_write(codec,
- aic3262_divs[i].codec_specific_regs[j].reg_offset,
- aic3262_divs[i].codec_specific_regs[j].reg_val);
- }
-
- /* Enable the PLL, MDAC, NDAC, NADC, MADC and BCLK Dividers */
- aic3262_set_bias_level(codec, SND_SOC_BIAS_ON);
-
- /* Based on the DAI ID we enable the corresponding pins related to the
- * ASI Port.
- */
- switch (dai->id) {
- case 1:
- aic3262_asi1_clk_config(codec, params);
- break;
- case 2:
- aic3262_asi2_clk_config(codec, params);
- break;
- case 3:
- aic3262_asi3_clk_config(codec, params);
- break;
- default:
- printk(KERN_ERR "Invalid Dai ID %d in %s",
- dai->id, __func__);
- break;
- }
- /* Depending on the DAI->ID update the local Flags */
- aic3262->asiCtxt[dai->id - 1].asi_active++;
- aic3262->asiCtxt[dai->id - 1].sampling_rate = params_rate(params);
- /* Update the active_count flag */
- aic3262->active_count++;
-
- return 0;
-}
-
-/*
-*
-* aic3262_multi_i2s_hw_free
-*
-* This function is used to configure the Codec after the usage is completed.
-* We can use this function to disable the DAC and ADC specific inputs from the
-* individual ASI Ports of the Audio Codec.
-*/
-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;
- struct snd_soc_codec *codec = rtd->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- u8 value;
- u8 dacpath;
- u8 adcpath;
- u16 dacregoffset = 0;
- u16 adcregoffset = 0;
-
- DBG(KERN_INFO "#%s: ASI%d Port for %s Mode\n",
- __func__, dai->id,
- (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
- "Playback" : "Record");
-
- /* Check if this function was already executed earlier for the same
- * ASI Port
- */
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
- (aic3262->asiCtxt[dai->id - 1].playback_mode == 0)) {
- DBG(KERN_INFO "#%s: Function Already Executed. Exiting..\n",
- __func__);
- goto err;
- } else if ((substream->stream != SNDRV_PCM_STREAM_PLAYBACK) &&
- (aic3262->asiCtxt[dai->id - 1].capture_mode == 0)) {
- DBG(KERN_INFO "#%s: Function Already Executed. Exiting..\n",
- __func__);
- goto err;
- }
-
- switch (dai->id) {
- case 1:
- /* In case we are Frame Master on this Interface, Switch off
- * the Bit Clock Divider and Word Clock Dividers
- */
- if (aic3262->asiCtxt[0].master == 1) {
- /* Also check if either Playback or Recording is still
- * going on this ASI Interface
- */
-
- value = snd_soc_read(codec, ASI1_BCLK_N);
- snd_soc_write(codec, ASI1_BCLK_N, (value & 0x7f));
-
- value = snd_soc_read(codec, ASI1_WCLK_N);
- snd_soc_write(codec, ASI1_WCLK_N, (value & 0x7f));
- }
-
- dacregoffset = ASI1_DAC_OUT_CNTL;
- adcregoffset = ASI1_ADC_INPUT_CNTL;
- break;
- case 2:
- /* In case we are Frame Master on this Interface, Switch off
- * the Bit Clock Divider and Word Clock Dividers
- */
- if (aic3262->asiCtxt[1].master == 1) {
- value = snd_soc_read(codec, ASI2_BCLK_N);
- snd_soc_write(codec, ASI2_BCLK_N, (value & 0x7f));
-
- value = snd_soc_read(codec, ASI2_WCLK_N);
- snd_soc_write(codec, ASI2_WCLK_N, (value & 0x7f));
- }
- dacregoffset = ASI2_DAC_OUT_CNTL;
- adcregoffset = ASI2_ADC_INPUT_CNTL;
- break;
- case 3:
- /* In case we are Frame Master on this Interface, Switch off
- * the Bit Clock Divider and Word Clock Dividers
- */
- if (aic3262->asiCtxt[2].master == 1) {
- value = snd_soc_read(codec, ASI3_BCLK_N);
- snd_soc_write(codec, ASI3_BCLK_N, (value & 0x7f));
-
- value = snd_soc_read(codec, ASI3_WCLK_N);
- snd_soc_write(codec, ASI3_WCLK_N, (value & 0x7f));
- }
- dacregoffset = ASI3_DAC_OUT_CNTL;
- adcregoffset = ASI3_ADC_INPUT_CNTL;
- break;
- default:
- printk(KERN_ERR "#%s: Invalid dai id\n", __func__);
- }
- /* If this was a Playback Stream Stop, then only
- * switch off the DAC Inputs
- */
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
- (dacregoffset != 0)) {
- DBG(KERN_INFO "#%s: Disabling Pg %d Reg %d DAC Inputs ..\n",
- __func__, (dacregoffset/128), (dacregoffset % 128));
-
- dacpath = snd_soc_read(codec, dacregoffset);
- snd_soc_write(codec, dacregoffset, (dacpath & ~(BIT6 | BIT4)));
-
- aic3262->asiCtxt[dai->id - 1].playback_mode = 0;
- } else {
- /* Switch off the ADC Input Control Registers here */
- DBG(KERN_INFO "#%s: Disabling Pg %d Reg %d for ADC Inputs..\n",
- __func__, (adcregoffset/128), (adcregoffset % 128));
-
- adcpath = snd_soc_read(codec, adcregoffset);
- snd_soc_write(codec, adcregoffset,
- (adcpath & ~(BIT2 | BIT1 | BIT0)));
-
- aic3262->asiCtxt[dai->id - 1].capture_mode = 0;
- }
-
- /* If we were configured in mono PCM Mode earlier, then reset the
- * Left Channel and Right Channel offset Registers here.
- */
- switch (dai->id) {
- case 1:
- if (aic3262->asiCtxt[0].pcm_format == SND_SOC_DAIFMT_DSP_B) {
- snd_soc_write(codec, ASI1_LCH_OFFSET, 0x00);
- snd_soc_write(codec, ASI1_RCH_OFFSET, 0x00);
- }
- break;
- case 2:
- if (aic3262->asiCtxt[1].pcm_format == SND_SOC_DAIFMT_DSP_B) {
- snd_soc_write(codec, ASI2_LCH_OFFSET, 0x00);
- snd_soc_write(codec, ASI2_RCH_OFFSET, 0x00);
- }
-
- break;
- case 3:
- if (aic3262->asiCtxt[2].pcm_format == SND_SOC_DAIFMT_DSP_B) {
- snd_soc_write(codec, ASI3_LCH_OFFSET, 0x00);
- snd_soc_write(codec, ASI3_RCH_OFFSET, 0x00);
- }
- break;
- }
- /* Depending on the DAI->ID update the asi_active Flags */
- if (aic3262->asiCtxt[dai->id - 1].asi_active) {
- aic3262->asiCtxt[dai->id - 1].asi_active--;
-
- /* Update the active_count flag */
- if (aic3262->active_count)
- aic3262->active_count--;
- }
-err:
- return;
-}
-
-
-/*
-*
-* aic3262_multi_i2s_set_clkdiv
-*
-*/
-static int aic3262_multi_i2s_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
-{
- int value;
- struct snd_soc_codec *codec = codec_dai->codec;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
-
- value = snd_soc_read(codec, div_id);
- snd_soc_write(codec, div_id, (value | div));
-
- printk(KERN_INFO "#%s: DAI ID %d Page %d Register %d Divider_Val %d Final_Value 0x%x\n",
- __func__, codec_dai->id, (div_id /128), (div_id%128), div,
- (value | div));
-
- /* Store the Clock Divider inside the Private Structure */
- switch(codec_dai->id) {
- case 1:
- if (div_id == ASI1_BCLK_N)
- aic3262->asiCtxt[0].bclk_div = div;
- if (div_id == ASI1_WCLK_N)
- aic3262->asiCtxt[0].wclk_div = div;
- break;
- case 2:
- if (div_id == ASI2_BCLK_N)
- aic3262->asiCtxt[1].bclk_div = div;
- if (div_id == ASI2_WCLK_N)
- aic3262->asiCtxt[1].wclk_div = div;
- break;
- case 3:
- if (div_id == ASI3_BCLK_N)
- aic3262->asiCtxt[2].bclk_div = div;
- if (div_id == ASI3_WCLK_N)
- aic3262->asiCtxt[2].wclk_div = div;
- break;
- }
- return 0;
-}
-
-
/*
*----------------------------------------------------------------------------
* @struct snd_soc_codec_dai |
- * It is SoC Codec DAI structure which has DAI capabilities viz.,
- * playback and capture, DAI runtime information viz. state of DAI
+ * It is SoC Codec DAI structure which has DAI capabilities viz.,
+ * playback and capture, DAI runtime information viz. state of DAI
* and pop wait state, and DAI private data.
- * The AIC3262 rates ranges from 8k to 192k
- * The PCM bit format supported are 16, 20, 24 and 32 bits
+ * The AIC3262 rates ranges from 8k to 192k
+ * The PCM bit format supported are 16, 20, 24 and 32 bits
*----------------------------------------------------------------------------
*/
-struct snd_soc_dai_ops aic3262_multi_i2s_dai_ops = {
- .hw_params = aic3262_multi_i2s_hw_params,
- .digital_mute = aic3262_multi_i2s_mute,
- .set_fmt = aic3262_multi_i2s_set_dai_fmt,
- .set_pll = aic3262_multi_i2s_set_dai_pll,
- .set_sysclk = aic3262_multi_i2s_set_dai_sysclk,
- .shutdown = aic3262_multi_i2s_shutdown,
- .set_clkdiv = aic3262_multi_i2s_set_clkdiv,
+struct snd_soc_dai_ops aic3262_asi1_dai_ops = {
+ .hw_params = aic3262_hw_params,
+ .digital_mute = aic3262_mute,
+ .set_sysclk = aic3262_set_dai_sysclk,
+ .set_fmt = aic3262_set_dai_fmt,
+ .set_pll = aic3262_dai_set_pll,
};
-
-static struct snd_soc_dai_driver tlv320aic3262_dai[] = {
-/* AIC3262 ASI1 DAI */
-{
- .name = "aic3262-asi1",
- .id = 1,
- .playback = {
- .stream_name = "ASI1 Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = AIC3262_RATES,
- .formats = AIC3262_FORMATS},
- .capture = { /* dummy for fast DAI switching */
- .stream_name = "ASI1 Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = AIC3262_RATES,
- .formats = AIC3262_FORMATS},
- .ops = &aic3262_multi_i2s_dai_ops,
-},
-/* AIC3262 ASI2 DAI */
-{
- .name = "aic3262-asi2",
- .id = 2,
- .playback = {
- .stream_name = "ASI2 Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = AIC3262_RATES,
- .formats = AIC3262_FORMATS,},
- .capture = {
- .stream_name = "ASI2 Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = AIC3262_RATES,
- .formats = AIC3262_FORMATS,},
- .ops = &aic3262_multi_i2s_dai_ops,
-
-},
-/* AIC3262 ASI3 DAI */
-{
- .name = "aic3262-asi3",
- .id = 3,
- .playback = {
- .stream_name = "ASI3 Playback",
- .channels_min = 1,
- .channels_max = 2,
- .rates = AIC3262_RATES,
- .formats = AIC3262_FORMATS, },
- .capture = {
- .stream_name = "ASI3 Capture",
- .channels_min = 1,
- .channels_max = 2,
- .rates = AIC3262_RATES,
- .formats = AIC3262_FORMATS, },
- .ops = &aic3262_multi_i2s_dai_ops,
-
-},
+struct snd_soc_dai_ops aic3262_asi2_dai_ops = {
+ .hw_params = aic3262_hw_params,
+ .digital_mute = aic3262_mute,
+ .set_sysclk = aic3262_set_dai_sysclk,
+ .set_fmt = aic3262_set_dai_fmt,
+ .set_pll = aic3262_dai_set_pll,
};
-/*
- *****************************************************************************
- * Initializations
- *****************************************************************************
- */
-/*
- * AIC3262 register cache
- * We are caching the registers here.
- * There is no point in caching the reset register.
- *
- * NOTE: In AIC3262, there are 127 registers supported in both page0 and page1
- * The following table contains the page0 and page 1 and page 3
- * registers values.
- */
-static const u8 aic3262_reg[AIC3262_CACHEREGNUM] = {
- 0x00, 0x00, 0x10, 0x00, /* 0 */
- 0x03, 0x40, 0x11, 0x08, /* 4 */
- 0x00, 0x00, 0x00, 0x82, /* 8 */
- 0x88, 0x00, 0x80, 0x02, /* 12 */
- 0x00, 0x08, 0x01, 0x01, /* 16 */
- 0x80, 0x01, 0x00, 0x04, /* 20 */
- 0x00, 0x00, 0x01, 0x00, /* 24 */
- 0x00, 0x00, 0x01, 0x00, /* 28 */
- 0x00, 0x00, 0x00, 0x00, /* 32 */
- 0x00, 0x00, 0x00, 0x00, /* 36 */
- 0x00, 0x00, 0x00, 0x00, /* 40 */
- 0x00, 0x00, 0x00, 0x00, /* 44 */
- 0x00, 0x00, 0x00, 0x00, /* 48 */
- 0x00, 0x42, 0x02, 0x02, /* 52 */
- 0x42, 0x02, 0x02, 0x02, /* 56 */
- 0x00, 0x00, 0x00, 0x01, /* 60 */
- 0x01, 0x00, 0x14, 0x00, /* 64 */
- 0x0C, 0x00, 0x00, 0x00, /* 68 */
- 0x00, 0x00, 0x00, 0xEE, /* 72 */
- 0x10, 0xD8, 0x10, 0xD8, /* 76 */
- 0x00, 0x00, 0x88, 0x00, /* 80 */
- 0x00, 0x00, 0x00, 0x00, /* 84 */
- 0x7F, 0x00, 0x00, 0x00, /* 88 */
- 0x00, 0x00, 0x00, 0x00, /* 92 */
- 0x7F, 0x00, 0x00, 0x00, /* 96 */
- 0x00, 0x00, 0x00, 0x00, /* 100 */
- 0x00, 0x00, 0x00, 0x00, /* 104 */
- 0x00, 0x00, 0x00, 0x00, /* 108 */
- 0x00, 0x00, 0x00, 0x00, /* 112 */
- 0x00, 0x00, 0x00, 0x00, /* 116 */
- 0x00, 0x00, 0x00, 0x00, /* 120 */
- 0x00, 0x00, 0x00, 0x00, /* 124 - PAGE0 Registers(127) ends here */
- 0x01, 0x00, 0x08, 0x00, /* 128, PAGE1-0 */
- 0x00, 0x00, 0x00, 0x00, /* 132, PAGE1-4 */
- 0x00, 0x00, 0x00, 0x10, /* 136, PAGE1-8 */
- 0x00, 0x00, 0x00, 0x00, /* 140, PAGE1-12 */
- 0x40, 0x40, 0x40, 0x40, /* 144, PAGE1-16 */
- 0x00, 0x00, 0x00, 0x00, /* 148, PAGE1-20 */
- 0x00, 0x00, 0x00, 0x00, /* 152, PAGE1-24 */
- 0x00, 0x00, 0x00, 0x00, /* 156, PAGE1-28 */
- 0x00, 0x00, 0x00, 0x00, /* 160, PAGE1-32 */
- 0x00, 0x00, 0x00, 0x00, /* 164, PAGE1-36 */
- 0x00, 0x00, 0x00, 0x00, /* 168, PAGE1-40 */
- 0x00, 0x00, 0x00, 0x00, /* 172, PAGE1-44 */
- 0x00, 0x00, 0x00, 0x00, /* 176, PAGE1-48 */
- 0x00, 0x00, 0x00, 0x00, /* 180, PAGE1-52 */
- 0x00, 0x00, 0x00, 0x80, /* 184, PAGE1-56 */
- 0x80, 0x00, 0x00, 0x00, /* 188, PAGE1-60 */
- 0x00, 0x00, 0x00, 0x00, /* 192, PAGE1-64 */
- 0x00, 0x00, 0x00, 0x00, /* 196, PAGE1-68 */
- 0x00, 0x00, 0x00, 0x00, /* 200, PAGE1-72 */
- 0x00, 0x00, 0x00, 0x00, /* 204, PAGE1-76 */
- 0x00, 0x00, 0x00, 0x00, /* 208, PAGE1-80 */
- 0x00, 0x00, 0x00, 0x00, /* 212, PAGE1-84 */
- 0x00, 0x00, 0x00, 0x00, /* 216, PAGE1-88 */
- 0x00, 0x00, 0x00, 0x00, /* 220, PAGE1-92 */
- 0x00, 0x00, 0x00, 0x00, /* 224, PAGE1-96 */
- 0x00, 0x00, 0x00, 0x00, /* 228, PAGE1-100 */
- 0x00, 0x00, 0x00, 0x00, /* 232, PAGE1-104 */
- 0x00, 0x00, 0x00, 0x00, /* 236, PAGE1-108 */
- 0x00, 0x00, 0x00, 0x00, /* 240, PAGE1-112 */
- 0x00, 0x00, 0x00, 0x00, /* 244, PAGE1-116 */
- 0x00, 0x00, 0x00, 0x00, /* 248, PAGE1-120 */
- 0x00, 0x00, 0x00, 0x00, /* 252, PAGE1-124 Page 1 Registers Ends Here */
- 0x00, 0x00, 0x00, 0x00, /* 256, PAGE2-0 */
- 0x00, 0x00, 0x00, 0x00, /* 260, PAGE2-4 */
- 0x00, 0x00, 0x00, 0x00, /* 264, PAGE2-8 */
- 0x00, 0x00, 0x00, 0x00, /* 268, PAGE2-12 */
- 0x00, 0x00, 0x00, 0x00, /* 272, PAGE2-16 */
- 0x00, 0x00, 0x00, 0x00, /* 276, PAGE2-20 */
- 0x00, 0x00, 0x00, 0x00, /* 280, PAGE2-24 */
- 0x00, 0x00, 0x00, 0x00, /* 284, PAGE2-28 */
- 0x00, 0x00, 0x00, 0x00, /* 288, PAGE2-32 */
- 0x00, 0x00, 0x00, 0x00, /* 292, PAGE2-36 */
- 0x00, 0x00, 0x00, 0x00, /* 296, PAGE2-40 */
- 0x00, 0x00, 0x00, 0x00, /* 300, PAGE2-44 */
- 0x00, 0x00, 0x00, 0x00, /* 304, PAGE2-48 */
- 0x00, 0x00, 0x00, 0x00, /* 308, PAGE2-52 */
- 0x00, 0x00, 0x00, 0x00, /* 312, PAGE2-56 */
- 0x00, 0x00, 0x00, 0x00, /* 316, PAGE2-60 */
- 0x00, 0x00, 0x00, 0x00, /* 320, PAGE2-64 */
- 0x00, 0x00, 0x00, 0x00, /* 324, PAGE2-68 */
- 0x00, 0x00, 0x00, 0x00, /* 328, PAGE2-72 */
- 0x00, 0x00, 0x00, 0x00, /* 332, PAGE2-76 */
- 0x00, 0x00, 0x00, 0x00, /* 336, PAGE2-80 */
- 0x00, 0x00, 0x00, 0x00, /* 340, PAGE2-84 */
- 0x00, 0x00, 0x00, 0x00, /* 344, PAGE2-88 */
- 0x00, 0x00, 0x00, 0x00, /* 348, PAGE2-92 */
- 0x00, 0x00, 0x00, 0x00, /* 352, PAGE2-96 */
- 0x00, 0x00, 0x00, 0x00, /* 356, PAGE2-100 */
- 0x00, 0x00, 0x00, 0x00, /* 360, PAGE2-104 */
- 0x00, 0x00, 0x00, 0x00, /* 364, PAGE2-108 */
- 0x00, 0x00, 0x00, 0x00, /* 368, PAGE2-112*/
- 0x00, 0x00, 0x00, 0x00, /* 372, PAGE2-116*/
- 0x00, 0x00, 0x00, 0x00, /* 376, PAGE2-120*/
- 0x00, 0x00, 0x00, 0x00, /* 380, PAGE2-124 Page 2 Registers Ends Here */
- 0x00, 0x00, 0x00, 0x00, /* 384, PAGE3-0 */
- 0x00, 0x00, 0x00, 0x00, /* 388, PAGE3-4 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-8 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-12 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-16 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-20 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-24 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-28 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-32 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-36 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-40 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-44 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-48 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-52 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-56 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-60 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-64 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE3-68 */
- 0x00, 0x00, 0x00, 0x00, /* 328, PAGE3-72 */
- 0x00, 0x00, 0x00, 0x00, /* 332, PAGE3-76 */
- 0x00, 0x00, 0x00, 0x00, /* 336, PAGE3-80 */
- 0x00, 0x00, 0x00, 0x00, /* 340, PAGE3-84 */
- 0x00, 0x00, 0x00, 0x00, /* 344, PAGE3-88 */
- 0x00, 0x00, 0x00, 0x00, /* 348, PAGE3-92 */
- 0x00, 0x00, 0x00, 0x00, /* 352, PAGE3-96 */
- 0x00, 0x00, 0x00, 0x00, /* 356, PAGE3-100 */
- 0x00, 0x00, 0x00, 0x00, /* 360, PAGE3-104 */
- 0x00, 0x00, 0x00, 0x00, /* 364, PAGE3-108 */
- 0x00, 0x00, 0x00, 0x00, /* 368, PAGE3-112*/
- 0x00, 0x00, 0x00, 0x00, /* 372, PAGE3-116*/
- 0x00, 0x00, 0x00, 0x00, /* 376, PAGE3-120*/
- 0x00, 0x00, 0x00, 0x00, /* 380, PAGE3-124 Page 3 Registers Ends Here */
- 0x00, 0x00, 0x00, 0x00, /* 384, PAGE4-0 */
- 0x00, 0x00, 0x00, 0x00, /* 388, PAGE4-4 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-8 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-12 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-16 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-20 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-24 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-28 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-32 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-36 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-40 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-44 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-48 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-52 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-56 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-60 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-64 */
- 0x00, 0x00, 0x00, 0x00, /* 392, PAGE4-68 */
- 0x00, 0x00, 0x00, 0x00, /* 328, PAGE4-72 */
- 0x00, 0x00, 0x00, 0x00, /* 332, PAGE4-76 */
- 0x00, 0x00, 0x00, 0x00, /* 336, PAGE4-80 */
- 0x00, 0x00, 0x00, 0x00, /* 340, PAGE4-84 */
- 0x00, 0x00, 0x00, 0x00, /* 344, PAGE4-88 */
- 0x00, 0x00, 0x00, 0x00, /* 348, PAGE4-92 */
- 0x00, 0x00, 0x00, 0x00, /* 352, PAGE4-96 */
- 0x00, 0x00, 0x00, 0x00, /* 356, PAGE4-100 */
- 0x00, 0x00, 0x00, 0x00, /* 360, PAGE4-104 */
- 0x00, 0x00, 0x00, 0x00, /* 364, PAGE4-108 */
- 0x00, 0x00, 0x00, 0x00, /* 368, PAGE4-112*/
- 0x00, 0x00, 0x00, 0x00, /* 372, PAGE4-116*/
- 0x00, 0x00, 0x00, 0x00, /* 376, PAGE4-120*/
- 0x00, 0x00, 0x00, 0x00, /* 380, PAGE4-124 Page 2 Registers Ends Here */
-
+struct snd_soc_dai_ops aic3262_asi3_dai_ops = {
+ .hw_params = aic3262_hw_params,
+ .digital_mute = aic3262_mute,
+ .set_sysclk = aic3262_set_dai_sysclk,
+ .set_fmt = aic3262_set_dai_fmt,
+ .set_pll = aic3262_dai_set_pll,
};
-/*
- *------------------------------------------------------------------------------
- * aic3262 initialization data
- * This structure initialization contains the initialization required for
- * AIC326x.
- * These registers values (reg_val) are written into the respective AIC3262
- * register offset (reg_offset) to initialize AIC326x.
- * These values are used in aic3262_init() function only.
- *------------------------------------------------------------------------------
- */
-static const struct aic3262_configs aic3262_reg_init[] = {
- /* CLOCKING */
-
- {0, RESET_REG, 1},
- {0, RESET_REG, 0},
-
- {0, PASI_DAC_DP_SETUP, 0xc0}, /*DAC */
- {0, DAC_MVOL_CONF, 0x00}, /*DAC un-muted*/
- /* set default volumes */
- {0, DAC_LVOL, 0x01},
- {0, DAC_RVOL, 0x01},
- {0, HPL_VOL, 0x80},
- {0, HPR_VOL, 0x80},
- {0, SPK_AMP_CNTL_R2, 0x14},
- {0, SPK_AMP_CNTL_R3, 0x14},
- {0, SPK_AMP_CNTL_R4, 0x33},
- {0, REC_AMP_CNTL_R5, 0x82},
- {0, RAMPR_VOL, 20},
- {0, RAMP_CNTL_R1, 70},
- {0, RAMP_CNTL_R2, 70},
-
- /* DRC Defaults */
- {0, DRC_CNTL_R1, 0x6c},
- {0, DRC_CNTL_R2, 16},
-
- /* DEPOP SETTINGS */
- {0, HP_DEPOP, 0x14},
- {0, RECV_DEPOP, 0x14},
-
- {0, POWER_CONF, 0x00}, /* Disconnecting AVDD-DVD weak link*/
- {0, REF_PWR_DLY, 0x01},
- {0, CM_REG, 0x00}, /*CM - default*/
- {0, LDAC_PTM, 0}, /*LDAC_PTM - default*/
- {0, RDAC_PTM, 0}, /*RDAC_PTM - default*/
- {0, HP_CTL, 0x30}, /*HP output percentage - at 75%*/
- {0, LADC_VOL, 0x01}, /*LADC volume*/
- {0, RADC_VOL, 0x01}, /*RADC volume*/
-
- {0, DAC_ADC_CLKIN_REG, 0x33}, /*DAC ADC CLKIN*/
- {0, PLL_CLKIN_REG, 0x00}, /*PLL CLKIN*/
- {0, PLL_PR_POW_REG, 0x11}, /*PLL Power=0-down, P=1, R=1 vals*/
- {0, 0x3d, 1},
-
- {0, LMIC_PGA_PIN, 0x0}, /*IN1_L select - - 10k -LMICPGA_P*/
- {0, LMIC_PGA_MIN, 0x40}, /*CM to LMICPGA-M*/
- {0, RMIC_PGA_PIN, 0x0}, /*IN1_R select - - 10k -RMIC_PGA_P*/
- {0, RMIC_PGA_MIN, 0x0}, /*CM to RMICPGA_M*/
- {0, MIC_PWR_DLY , 33}, /*LMIC-PGA-POWERUP-DELAY - default*/
- {0, REF_PWR_DLY, 1}, /*FIXMELATER*/
-
-
- {0, ADC_CHANNEL_POW, 0x0}, /*ladc, radc ON , SOFT STEP disabled*/
- {0, ADC_FINE_GAIN, 0x00}, /*ladc - unmute, radc - unmute*/
- {0, MICL_PGA, 0x3f},
- {0, MICR_PGA, 0x3f},
- /*controls MicBias ext power based on B0_P1_R51_D6*/
- {0, MIC_BIAS_CNTL, 0x80},
- /* ASI1 Configuration */
- {0, ASI1_BUS_FMT, 0},
- {0, ASI1_BWCLK_CNTL_REG, 0x00}, /* originaly 0x24*/
- {0, ASI1_BCLK_N_CNTL, 1},
- {0, ASI1_BCLK_N, 0x04},
-
- {0, MA_CNTL, 0}, /* Mixer Amp disabled */
- {0, LINE_AMP_CNTL_R2, 0x00}, /* Line Amp Cntl disabled */
-
- /* ASI2 Configuration */
- {0, ASI2_BUS_FMT, 0},
- {0, ASI2_BCLK_N_CNTL, 0x01},
- {0, ASI2_BCLK_N, 0x04},
- {0, ASI2_BWCLK_OUT_CNTL, 0x20},
-
- {0, BEEP_CNTL_R1, 0x05},
- {0, BEEP_CNTL_R2, 0x04},
-
- /* Interrupt config for headset detection */
- {0,HEADSET_TUNING1_REG,0x7f},
- {0, INT1_CNTL, 0x40},
- /*{0, TIMER_REG, 0x8c},*/
- {0, INT_FMT, 0x40},
- {0, GPIO1_IO_CNTL, 0x14},
- {0, HP_DETECT, 0x96},
-
-#if defined(CONFIG_MINI_DSP)
- {0, 60, 0},
- {0, 61, 0},
- /* Added the below set of values after consulting the miniDSP
- * Program Section Array
- */
- {0, MINIDSP_ACCESS_CTRL, 0x00},
-#endif
-
+struct snd_soc_dai_driver aic326x_dai_driver[] = {
+ {
+ .name = "aic326x-asi1",
+ .playback = {
+ .stream_name = "ASI1 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC3262_RATES,
+ .formats = AIC3262_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASI1 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC3262_RATES,
+ .formats = AIC3262_FORMATS,
+ },
+ .ops = &aic3262_asi1_dai_ops,
+ },
+ {
+ .name = "aic326x-asi2",
+ .playback = {
+ .stream_name = "ASI2 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC3262_RATES,
+ .formats = AIC3262_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASI2 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC3262_RATES,
+ .formats = AIC3262_FORMATS,
+ },
+ .ops = &aic3262_asi2_dai_ops,
+ },
+ {
+ .name = "aic326x-asi3",
+ .playback = {
+ .stream_name = "ASI3 Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC3262_RATES,
+ .formats = AIC3262_FORMATS,
+ },
+ .capture = {
+ .stream_name = "ASI3 Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = AIC3262_RATES,
+ .formats = AIC3262_FORMATS,
+ },
+ .ops = &aic3262_asi3_dai_ops,
+ },
};
-static int reg_init_size =
- sizeof(aic3262_reg_init) / sizeof(struct aic3262_configs);
static const unsigned int adc_ma_tlv[] = {
-TLV_DB_RANGE_HEAD(4),
+ TLV_DB_RANGE_HEAD(4),
0, 29, TLV_DB_SCALE_ITEM(-1450, 500, 0),
30, 35, TLV_DB_SCALE_ITEM(-2060, 1000, 0),
36, 38, TLV_DB_SCALE_ITEM(-2660, 2000, 0),
39, 40, TLV_DB_SCALE_ITEM(-3610, 5000, 0),
};
-static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0);
+static const DECLARE_TLV_DB_SCALE(lo_hp_tlv, -7830, 50, 0);
static const struct snd_kcontrol_new mal_pga_mixer_controls[] = {
- SOC_DAPM_SINGLE("IN1L Switch", MA_CNTL, 5, 1, 0),
- SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", LADC_PGA_MAL_VOL, 0,
- 0x3f, 1, adc_ma_tlv),
-
+ SOC_DAPM_SINGLE("IN1L Switch", AIC3262_MA_CNTL, 5, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Left MicPGA Volume", AIC3262_LADC_PGA_MAL_VOL,
+ 0, 0x3f, 1, adc_ma_tlv),
};
static const struct snd_kcontrol_new mar_pga_mixer_controls[] = {
- SOC_DAPM_SINGLE("IN1R Switch", MA_CNTL, 4, 1, 0),
- SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", RADC_PGA_MAR_VOL, 0,
- 0x3f, 1, adc_ma_tlv),
+ SOC_DAPM_SINGLE("IN1R Switch", AIC3262_MA_CNTL, 4, 1, 0),
+ SOC_DAPM_SINGLE_TLV("Right MicPGA Volume", AIC3262_RADC_PGA_MAR_VOL,
+ 0, 0x3f, 1, adc_ma_tlv),
};
/* Left HPL Mixer */
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, 0, lo_hp_tlv),
+ SOC_DAPM_SINGLE("MAL Switch", AIC3262_HP_AMP_CNTL_R1, 7, 1,
+ 0),
+ SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1,
+ 5, 1, 0),
+ SOC_DAPM_SINGLE_TLV("LOL-B1 Volume",
+ AIC3262_HP_AMP_CNTL_R2, 0, 0x7f, 1, 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, 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),
+ SOC_DAPM_SINGLE_TLV("LOR-B1 Volume",
+ AIC3262_HP_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv),
+ SOC_DAPM_SINGLE("LDAC Switch", AIC3262_HP_AMP_CNTL_R1,
+ 2, 1, 0),
+ SOC_DAPM_SINGLE("RDAC Switch", AIC3262_HP_AMP_CNTL_R1,
+ 4, 1, 0),
+ SOC_DAPM_SINGLE("MAR Switch", AIC3262_HP_AMP_CNTL_R1,
+ 6, 1, 0),
};
/* Left LOL Mixer */
static const struct snd_kcontrol_new lol_output_mixer_controls[] = {
- SOC_DAPM_SINGLE("MAL Switch", LINE_AMP_CNTL_R2, 7, 1, 0),
- SOC_DAPM_SINGLE("IN1L-B Switch", LINE_AMP_CNTL_R2, 3, 1,0),
- SOC_DAPM_SINGLE("LDAC Switch", LINE_AMP_CNTL_R1, 7, 1, 0),
- SOC_DAPM_SINGLE("RDAC Switch", LINE_AMP_CNTL_R1, 5, 1, 0),
+ SOC_DAPM_SINGLE("MAL Switch", AIC3262_LINE_AMP_CNTL_R2,
+ 7, 1, 0),
+ SOC_DAPM_SINGLE("IN1L-B Switch", AIC3262_LINE_AMP_CNTL_R2,
+ 3, 1, 0),
+ SOC_DAPM_SINGLE("LDAC Switch", AIC3262_LINE_AMP_CNTL_R1,
+ 7, 1, 0),
+ SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1,
+ 5, 1, 0),
};
/* Right LOR Mixer */
static const struct snd_kcontrol_new lor_output_mixer_controls[] = {
- SOC_DAPM_SINGLE("LOL Switch", LINE_AMP_CNTL_R1, 2, 1, 0),
- SOC_DAPM_SINGLE("RDAC Switch", LINE_AMP_CNTL_R1, 6, 1, 0),
- SOC_DAPM_SINGLE("MAR Switch", LINE_AMP_CNTL_R2, 6, 1, 0),
- SOC_DAPM_SINGLE("IN1R-B Switch", LINE_AMP_CNTL_R2, 0, 1,0),
+ SOC_DAPM_SINGLE("LOL Switch", AIC3262_LINE_AMP_CNTL_R1,
+ 2, 1, 0),
+ SOC_DAPM_SINGLE("RDAC Switch", AIC3262_LINE_AMP_CNTL_R1,
+ 6, 1, 0),
+ SOC_DAPM_SINGLE("MAR Switch", AIC3262_LINE_AMP_CNTL_R2,
+ 6, 1, 0),
+ SOC_DAPM_SINGLE("IN1R-B Switch", AIC3262_LINE_AMP_CNTL_R2,
+ 0, 1, 0),
};
/* Left SPKL Mixer */
static const struct snd_kcontrol_new spkl_output_mixer_controls[] = {
- SOC_DAPM_SINGLE("MAL Switch", SPK_AMP_CNTL_R1, 7, 1, 0),
- SOC_DAPM_SINGLE_TLV("LOL Volume", SPK_AMP_CNTL_R2, 0, 0x7f,0,
- lo_hp_tlv),
- SOC_DAPM_SINGLE("SPR_IN Switch", SPK_AMP_CNTL_R1, 2, 1, 0),
+ SOC_DAPM_SINGLE("MAL Switch", AIC3262_SPK_AMP_CNTL_R1,
+ 7, 1, 0),
+ SOC_DAPM_SINGLE_TLV("LOL Volume",
+ AIC3262_SPK_AMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv),
+ SOC_DAPM_SINGLE("SPR_IN Switch", AIC3262_SPK_AMP_CNTL_R1, 2, 1, 0),
};
/* Right SPKR Mixer */
static const struct snd_kcontrol_new spkr_output_mixer_controls[] = {
- SOC_DAPM_SINGLE_TLV("LOR Volume", SPK_AMP_CNTL_R3, 0, 0x7f, 0,
- lo_hp_tlv),
- SOC_DAPM_SINGLE("MAR Switch", SPK_AMP_CNTL_R1, 6, 1, 0),
+ SOC_DAPM_SINGLE_TLV("LOR Volume",
+ AIC3262_SPK_AMP_CNTL_R3, 0, 0x7f, 1, lo_hp_tlv),
+ SOC_DAPM_SINGLE("MAR Switch",
+ AIC3262_SPK_AMP_CNTL_R1, 6, 1, 0),
};
/* REC Mixer */
static const struct snd_kcontrol_new rec_output_mixer_controls[] = {
- SOC_DAPM_SINGLE_TLV("LOL-B2 Volume", RAMP_CNTL_R1, 0, 0x7f,0,
- lo_hp_tlv),
- SOC_DAPM_SINGLE_TLV("IN1L Volume", IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv),
- SOC_DAPM_SINGLE_TLV("IN1R Volume", IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv),
- SOC_DAPM_SINGLE_TLV("LOR-B2 Volume", RAMP_CNTL_R2, 0,0x7f, 0,lo_hp_tlv),
+ SOC_DAPM_SINGLE_TLV("LOL-B2 Volume",
+ AIC3262_RAMP_CNTL_R1, 0, 0x7f, 1, lo_hp_tlv),
+ SOC_DAPM_SINGLE_TLV("IN1L Volume",
+ AIC3262_IN1L_SEL_RM, 0, 0x7f, 1, lo_hp_tlv),
+ SOC_DAPM_SINGLE_TLV("IN1R Volume",
+ AIC3262_IN1R_SEL_RM, 0, 0x7f, 1, lo_hp_tlv),
+ SOC_DAPM_SINGLE_TLV("LOR-B2 Volume",
+ AIC3262_RAMP_CNTL_R2, 0, 0x7f, 1, lo_hp_tlv),
};
/* Left Input Mixer */
static const struct snd_kcontrol_new left_input_mixer_controls[] = {
- SOC_DAPM_SINGLE("IN1L Switch", LMIC_PGA_PIN, 6, 1, 0),
- SOC_DAPM_SINGLE("IN2L Switch", LMIC_PGA_PIN, 4, 1, 0),
- SOC_DAPM_SINGLE("IN3L Switch", LMIC_PGA_PIN, 2, 1, 0),
- SOC_DAPM_SINGLE("IN4L Switch", LMIC_PGA_PM_IN4, 5, 1, 0),
- SOC_DAPM_SINGLE("IN1R Switch", LMIC_PGA_PIN, 0, 1, 0),
- SOC_DAPM_SINGLE("IN2R Switch", LMIC_PGA_MIN, 4, 1, 0),
- SOC_DAPM_SINGLE("IN3R Switch", LMIC_PGA_MIN, 2, 1, 0),
- SOC_DAPM_SINGLE("IN4R Switch", LMIC_PGA_PM_IN4, 4, 1, 0),
- SOC_DAPM_SINGLE("CM2L Switch", LMIC_PGA_MIN, 0, 1, 0),
- SOC_DAPM_SINGLE("CM1L Switch", LMIC_PGA_MIN, 6, 1, 0),
+ SOC_DAPM_SINGLE("IN1L Switch", AIC3262_LMIC_PGA_PIN,
+ 6, 3, 0),
+ SOC_DAPM_SINGLE("IN2L Switch", AIC3262_LMIC_PGA_PIN,
+ 4, 3, 0),
+ SOC_DAPM_SINGLE("IN3L Switch", AIC3262_LMIC_PGA_PIN,
+ 2, 3, 0),
+ SOC_DAPM_SINGLE("IN4L Switch", AIC3262_LMIC_PGA_PM_IN4,
+ 5, 1, 0),
+ SOC_DAPM_SINGLE("IN1R Switch", AIC3262_LMIC_PGA_PIN,
+ 0, 3, 0),
+ SOC_DAPM_SINGLE("IN2R Switch", AIC3262_LMIC_PGA_MIN,
+ 4, 3, 0),
+ SOC_DAPM_SINGLE("IN3R Switch", AIC3262_LMIC_PGA_MIN,
+ 2, 3, 0),
+ SOC_DAPM_SINGLE("IN4R Switch", AIC3262_LMIC_PGA_PM_IN4,
+ 4, 1, 0),
+ SOC_DAPM_SINGLE("CM2L Switch", AIC3262_LMIC_PGA_MIN,
+ 0, 3, 0),
+ SOC_DAPM_SINGLE("CM1L Switch", AIC3262_LMIC_PGA_MIN,
+ 6, 3, 0),
};
/* Right Input Mixer */
static const struct snd_kcontrol_new right_input_mixer_controls[] = {
- SOC_DAPM_SINGLE("IN1R Switch", RMIC_PGA_PIN, 6, 1, 0),
- SOC_DAPM_SINGLE("IN2R Switch", RMIC_PGA_PIN, 4, 1, 0),
- SOC_DAPM_SINGLE("IN3R Switch", RMIC_PGA_PIN, 2, 1, 0),
- SOC_DAPM_SINGLE("IN4R Switch", RMIC_PGA_PM_IN4, 5, 1, 0),
- SOC_DAPM_SINGLE("IN2L Switch", RMIC_PGA_PIN, 0, 1, 0),
- SOC_DAPM_SINGLE("IN1L Switch", RMIC_PGA_MIN, 4, 1, 0),
- SOC_DAPM_SINGLE("IN3L Switch", RMIC_PGA_MIN, 2, 1, 0),
- SOC_DAPM_SINGLE("IN4L Switch", RMIC_PGA_PM_IN4, 4, 1, 0),
- SOC_DAPM_SINGLE("CM1R Switch", RMIC_PGA_MIN, 6, 1, 0),
- SOC_DAPM_SINGLE("CM2R Switch", RMIC_PGA_MIN, 0, 1, 0),
+ SOC_DAPM_SINGLE("IN1R Switch", AIC3262_RMIC_PGA_PIN,
+ 6, 3, 0),
+ SOC_DAPM_SINGLE("IN2R Switch", AIC3262_RMIC_PGA_PIN,
+ 4, 3, 0),
+ SOC_DAPM_SINGLE("IN3R Switch", AIC3262_RMIC_PGA_PIN,
+ 2, 3, 0),
+ SOC_DAPM_SINGLE("IN4R Switch", AIC3262_RMIC_PGA_PM_IN4,
+ 5, 1, 0),
+ SOC_DAPM_SINGLE("IN2L Switch", AIC3262_RMIC_PGA_PIN,
+ 0, 3, 0),
+ SOC_DAPM_SINGLE("IN1L Switch", AIC3262_RMIC_PGA_MIN,
+ 4, 3, 0),
+ SOC_DAPM_SINGLE("IN3L Switch", AIC3262_RMIC_PGA_MIN,
+ 2, 3, 0),
+ SOC_DAPM_SINGLE("IN4L Switch", AIC3262_RMIC_PGA_PM_IN4,
+ 4, 1, 0),
+ SOC_DAPM_SINGLE("CM1R Switch", AIC3262_RMIC_PGA_MIN,
+ 6, 3, 0),
+ SOC_DAPM_SINGLE("CM2R Switch", AIC3262_RMIC_PGA_MIN,
+ 0, 3, 0),
};
-
-static const char *asi1lin_text[] = {
- "Off", "ASI1 Left In","ASI1 Right In","ASI1 MonoMix In"
+static const char * const asi1lin_text[] = {
+ "Off", "ASI1 Left In", "ASI1 Right In", "ASI1 MonoMix In"
};
-SOC_ENUM_SINGLE_DECL(asi1lin_enum, ASI1_DAC_OUT_CNTL, 6, asi1lin_text);
+SOC_ENUM_SINGLE_DECL(asi1lin_enum, AIC3262_ASI1_DAC_OUT_CNTL, 6, asi1lin_text);
static const struct snd_kcontrol_new asi1lin_control =
- SOC_DAPM_ENUM("ASI1LIN Route", asi1lin_enum);
-
+SOC_DAPM_ENUM("ASI1LIN Route", asi1lin_enum);
-static const char *asi1rin_text[] = {
- "Off", "ASI1 Right In","ASI1 Left In","ASI1 MonoMix In"
+static const char * const asi1rin_text[] = {
+ "Off", "ASI1 Right In", "ASI1 Left In", "ASI1 MonoMix In"
};
-SOC_ENUM_SINGLE_DECL(asi1rin_enum, ASI1_DAC_OUT_CNTL, 4, asi1rin_text);
+SOC_ENUM_SINGLE_DECL(asi1rin_enum, AIC3262_ASI1_DAC_OUT_CNTL, 4, asi1rin_text);
static const struct snd_kcontrol_new asi1rin_control =
- SOC_DAPM_ENUM("ASI1RIN Route", asi1rin_enum);
+SOC_DAPM_ENUM("ASI1RIN Route", asi1rin_enum);
-static const char *asi2lin_text[] = {
- "Off", "ASI2 Left In","ASI2 Right In","ASI2 MonoMix In"
+static const char * const asi2lin_text[] = {
+ "Off", "ASI2 Left In", "ASI2 Right In", "ASI2 MonoMix In"
};
-SOC_ENUM_SINGLE_DECL(asi2lin_enum, ASI2_DAC_OUT_CNTL, 6, asi2lin_text);
+SOC_ENUM_SINGLE_DECL(asi2lin_enum, AIC3262_ASI2_DAC_OUT_CNTL, 6, asi2lin_text);
+
static const struct snd_kcontrol_new asi2lin_control =
- SOC_DAPM_ENUM("ASI2LIN Route", asi2lin_enum);
+SOC_DAPM_ENUM("ASI2LIN Route", asi2lin_enum);
-static const char *asi2rin_text[] = {
- "Off", "ASI2 Right In","ASI2 Left In","ASI2 MonoMix In"
+static const char * const asi2rin_text[] = {
+ "Off", "ASI2 Right In", "ASI2 Left In", "ASI2 MonoMix In"
};
-
-SOC_ENUM_SINGLE_DECL(asi2rin_enum, ASI2_DAC_OUT_CNTL, 4, asi2rin_text);
+SOC_ENUM_SINGLE_DECL(asi2rin_enum, AIC3262_ASI2_DAC_OUT_CNTL, 4, asi2rin_text);
static const struct snd_kcontrol_new asi2rin_control =
- SOC_DAPM_ENUM("ASI2RIN Route", asi2rin_enum);
+SOC_DAPM_ENUM("ASI2RIN Route", asi2rin_enum);
-static const char *asi3lin_text[] = {
- "Off", "ASI3 Left In","ASI3 Right In","ASI3 MonoMix In"
+static const char * const asi3lin_text[] = {
+ "Off", "ASI3 Left In", "ASI3 Right In", "ASI3 MonoMix In"
};
+SOC_ENUM_SINGLE_DECL(asi3lin_enum, AIC3262_ASI3_DAC_OUT_CNTL, 6, asi3lin_text);
-SOC_ENUM_SINGLE_DECL(asi3lin_enum, ASI3_DAC_OUT_CNTL, 6, asi3lin_text);
static const struct snd_kcontrol_new asi3lin_control =
- SOC_DAPM_ENUM("ASI3LIN Route", asi3lin_enum);
-
+SOC_DAPM_ENUM("ASI3LIN Route", asi3lin_enum);
-static const char *asi3rin_text[] = {
- "Off", "ASI3 Right In","ASI3 Left In","ASI3 MonoMix In"
+static const char * const asi3rin_text[] = {
+ "Off", "ASI3 Right In", "ASI3 Left In", "ASI3 MonoMix In"
};
+SOC_ENUM_SINGLE_DECL(asi3rin_enum, AIC3262_ASI3_DAC_OUT_CNTL, 4, asi3rin_text);
-SOC_ENUM_SINGLE_DECL(asi3rin_enum, ASI3_DAC_OUT_CNTL, 4, asi3rin_text);
static const struct snd_kcontrol_new asi3rin_control =
- SOC_DAPM_ENUM("ASI3RIN Route", asi3rin_enum);
+SOC_DAPM_ENUM("ASI3RIN Route", asi3rin_enum);
-
-static const char *dacminidspin1_text[] = {
- "ASI1 In", "ASI2 In","ASI3 In","ADC MiniDSP Out"
+static const char * const dacminidspin1_text[] = {
+ "ASI1 In", "ASI2 In", "ASI3 In", "ADC MiniDSP Out"
};
-SOC_ENUM_SINGLE_DECL(dacminidspin1_enum, MINIDSP_PORT_CNTL_REG, 4, dacminidspin1_text);
+SOC_ENUM_SINGLE_DECL(dacminidspin1_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 4,
+ dacminidspin1_text);
+
static const struct snd_kcontrol_new dacminidspin1_control =
- SOC_DAPM_ENUM("DAC MiniDSP IN1 Route", dacminidspin1_enum);
+SOC_DAPM_ENUM("DAC MiniDSP IN1 Route", dacminidspin1_enum);
-static const char *dacminidspin2_text[] = {
- "ASI1 In", "ASI2 In","ASI3 In"
+static const char * const dacminidspin2_text[] = {
+ "ASI1 In", "ASI2 In", "ASI3 In"
};
-//static const struct soc_enum dacminidspin1_enum =
-// SOC_ENUM_SINGLE(MINIDSP_DATA_PORT_CNTL, 5, 2, dacminidspin1_text);
-SOC_ENUM_SINGLE_DECL(dacminidspin2_enum, MINIDSP_PORT_CNTL_REG, 2, dacminidspin2_text);
+SOC_ENUM_SINGLE_DECL(dacminidspin2_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 2,
+ dacminidspin2_text);
static const struct snd_kcontrol_new dacminidspin2_control =
- SOC_DAPM_ENUM("DAC MiniDSP IN2 Route", dacminidspin2_enum);
+SOC_DAPM_ENUM("DAC MiniDSP IN2 Route", dacminidspin2_enum);
-static const char *dacminidspin3_text[] = {
- "ASI1 In", "ASI2 In","ASI3 In"
+static const char * const dacminidspin3_text[] = {
+ "ASI1 In", "ASI2 In", "ASI3 In"
};
-//static const struct soc_enum dacminidspin1_enum =
-// SOC_ENUM_SINGLE(MINIDSP_DATA_PORT_CNTL, 5, 2, dacminidspin1_text);
-SOC_ENUM_SINGLE_DECL(dacminidspin3_enum, MINIDSP_PORT_CNTL_REG, 0, dacminidspin3_text);
+SOC_ENUM_SINGLE_DECL(dacminidspin3_enum, AIC3262_MINIDSP_DATA_PORT_CNTL, 0,
+ dacminidspin3_text);
static const struct snd_kcontrol_new dacminidspin3_control =
SOC_DAPM_ENUM("DAC MiniDSP IN3 Route", dacminidspin3_enum);
-static const char *asi1out_text[] = {
+static const char * const adcdac_route_text[] = {
"Off",
+ "On",
+};
+
+SOC_ENUM_SINGLE_DECL(adcdac_enum, 0, 2, adcdac_route_text);
+
+static const struct snd_kcontrol_new adcdacroute_control =
+SOC_DAPM_ENUM_VIRT("ADC DAC Route", adcdac_enum);
+
+static const char * const dout1_text[] = {
"ASI1 Out",
+ "DIN1 Bypass",
+ "DIN2 Bypass",
+ "DIN3 Bypass",
+};
+
+SOC_ENUM_SINGLE_DECL(dout1_enum, AIC3262_ASI1_DOUT_CNTL, 0, dout1_text);
+static const struct snd_kcontrol_new dout1_control =
+SOC_DAPM_ENUM("DOUT1 Route", dout1_enum);
+
+static const char * const dout2_text[] = {
+ "ASI2 Out",
+ "DIN1 Bypass",
+ "DIN2 Bypass",
+ "DIN3 Bypass",
+};
+
+SOC_ENUM_SINGLE_DECL(dout2_enum, AIC3262_ASI2_DOUT_CNTL, 0, dout2_text);
+static const struct snd_kcontrol_new dout2_control =
+SOC_DAPM_ENUM("DOUT2 Route", dout2_enum);
+
+static const char * const dout3_text[] = {
+ "ASI3 Out",
+ "DIN1 Bypass",
+ "DIN2 Bypass",
+ "DIN3 Bypass",
+};
+
+SOC_ENUM_SINGLE_DECL(dout3_enum, AIC3262_ASI3_DOUT_CNTL, 0, dout3_text);
+static const struct snd_kcontrol_new dout3_control =
+SOC_DAPM_ENUM("DOUT3 Route", dout3_enum);
+
+static const char * const asi1out_text[] = {
+ "Off",
+ "ADC MiniDSP Out1",
"ASI1In Bypass",
"ASI2In Bypass",
"ASI3In Bypass",
};
-SOC_ENUM_SINGLE_DECL(asi1out_enum, ASI1_ADC_INPUT_CNTL, 0, asi1out_text);
+
+SOC_ENUM_SINGLE_DECL(asi1out_enum, AIC3262_ASI1_ADC_INPUT_CNTL,
+ 0, asi1out_text);
static const struct snd_kcontrol_new asi1out_control =
- SOC_DAPM_ENUM("ASI1OUT Route", asi1out_enum);
+SOC_DAPM_ENUM("ASI1OUT Route", asi1out_enum);
-static const char *asi2out_text[] = {
+static const char * const asi2out_text[] = {
"Off",
- "ASI1 Out",
+ "ADC MiniDSP Out1",
"ASI1In Bypass",
"ASI2In Bypass",
"ASI3In Bypass",
- "ASI2 Out",
+ "ADC MiniDSP Out2",
};
-SOC_ENUM_SINGLE_DECL(asi2out_enum, ASI2_ADC_INPUT_CNTL, 0, asi2out_text);
+
+SOC_ENUM_SINGLE_DECL(asi2out_enum, AIC3262_ASI2_ADC_INPUT_CNTL,
+ 0, asi2out_text);
static const struct snd_kcontrol_new asi2out_control =
- SOC_DAPM_ENUM("ASI2OUT Route", asi2out_enum);
-static const char *asi3out_text[] = {
+SOC_DAPM_ENUM("ASI2OUT Route", asi2out_enum);
+static const char * const asi3out_text[] = {
"Off",
- "ASI1 Out",
+ "ADC MiniDSP Out1",
"ASI1In Bypass",
"ASI2In Bypass",
"ASI3In Bypass",
- "ASI3 Out",
+ "Reserved",
+ "ADC MiniDSP Out3",
};
-SOC_ENUM_SINGLE_DECL(asi3out_enum, ASI3_ADC_INPUT_CNTL, 0, asi3out_text);
-static const struct snd_kcontrol_new asi3out_control =
- SOC_DAPM_ENUM("ASI3OUT Route", asi3out_enum);
-static const char *asi1bclk_text[] = {
+SOC_ENUM_SINGLE_DECL(asi3out_enum, AIC3262_ASI3_ADC_INPUT_CNTL,
+ 0, asi3out_text);
+static const struct snd_kcontrol_new asi3out_control =
+SOC_DAPM_ENUM("ASI3OUT Route", asi3out_enum);
+static const char * const asibclk_text[] = {
"DAC_CLK",
"DAC_MOD_CLK",
"ADC_CLK",
"ADC_MOD_CLK",
};
-SOC_ENUM_SINGLE_DECL(asi1bclk_enum, ASI1_BCLK_N_CNTL, 0, asi1bclk_text);
+SOC_ENUM_SINGLE_DECL(asi1bclk_enum, AIC3262_ASI1_BCLK_N_CNTL, 0, asibclk_text);
static const struct snd_kcontrol_new asi1bclk_control =
- SOC_DAPM_ENUM("ASI1_BCLK Route", asi1bclk_enum);
+SOC_DAPM_ENUM("ASI1_BCLK Route", asi1bclk_enum);
-static const char *asi2bclk_text[] = {
- "DAC_CLK",
- "DAC_MOD_CLK",
- "ADC_CLK",
- "ADC_MOD_CLK",
-};
-SOC_ENUM_SINGLE_DECL(asi2bclk_enum, ASI2_BCLK_N_CNTL, 0, asi2bclk_text);
+SOC_ENUM_SINGLE_DECL(asi2bclk_enum, AIC3262_ASI2_BCLK_N_CNTL, 0, asibclk_text);
static const struct snd_kcontrol_new asi2bclk_control =
- SOC_DAPM_ENUM("ASI2_BCLK Route", asi2bclk_enum);
-static const char *asi3bclk_text[] = {
- "DAC_CLK",
- "DAC_MOD_CLK",
- "ADC_CLK",
- "ADC_MOD_CLK",
-};
-SOC_ENUM_SINGLE_DECL(asi3bclk_enum, ASI3_BCLK_N_CNTL, 0, asi3bclk_text);
+SOC_DAPM_ENUM("ASI2_BCLK Route", asi2bclk_enum);
+SOC_ENUM_SINGLE_DECL(asi3bclk_enum, AIC3262_ASI3_BCLK_N_CNTL, 0, asibclk_text);
static const struct snd_kcontrol_new asi3bclk_control =
- SOC_DAPM_ENUM("ASI3_BCLK Route", asi3bclk_enum);
+SOC_DAPM_ENUM("ASI3_BCLK Route", asi3bclk_enum);
-static int aic326x_hp_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- return 0;
-}
-static int pll_power_on_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- if (event == SND_SOC_DAPM_POST_PMU)
- {
- mdelay(10);
- }
- return 0;
-}
+static const char * const adc_mux_text[] = {
+ "Analog",
+ "Digital",
+};
-static int polling_loop(struct snd_soc_codec *codec, unsigned int reg,
- int mask, int on_off)
-{
- unsigned int counter, status;
-
- counter = 0;
- switch(on_off) {
- case 0: /*off*/
- do {
- status = snd_soc_read(codec, reg);
- counter++;
- } while ((counter < 500) && ((status & mask) == mask));
- break;
- case 1: /*on*/
- do {
- status = snd_soc_read(codec, reg);
- counter++;
- } while ((counter < 500) && ((status & mask) != mask));
- break;
- default:
- printk("%s: unknown arguement\n", __func__);
- break;
- }
+SOC_ENUM_SINGLE_DECL(adcl_enum, AIC3262_ADC_CHANNEL_POW, 4, adc_mux_text);
+SOC_ENUM_SINGLE_DECL(adcr_enum, AIC3262_ADC_CHANNEL_POW, 2, adc_mux_text);
- printk("%s: exiting with count value %d \n", __func__, counter);
- if(counter >= 500)
- return -1;
- return 0;
-}
+static const struct snd_kcontrol_new adcl_mux =
+SOC_DAPM_ENUM("Left ADC Route", adcl_enum);
-int poll_dac(struct snd_soc_codec *codec, int left_right, int on_off)
-{
- int ret = 0;
+static const struct snd_kcontrol_new adcr_mux =
+SOC_DAPM_ENUM("Right ADC Route", adcr_enum);
- aic3262_change_page(codec, 0);
- aic3262_change_book(codec, 0);
-
- switch(on_off) {
-
- case 0:/*power off polling*/
- /*DAC power polling logic*/
- switch(left_right) {
- case 0: /*left dac polling*/
- ret = polling_loop(codec, DAC_FLAG_R1, LDAC_POW_FLAG_MASK, 0);
- break;
- case 1:/*right dac polling*/
- ret = polling_loop(codec, DAC_FLAG_R1, RDAC_POW_FLAG_MASK, 0);
- break;
- }
- break;
- case 1:/*power on polling*/
- /*DAC power polling logic*/
- switch(left_right) {
- case 0: /*left dac polling*/
- ret = polling_loop(codec, DAC_FLAG_R1, LDAC_POW_FLAG_MASK, 1);
- break;
- case 1:/*right dac polling*/
- ret = polling_loop(codec, DAC_FLAG_R1, RDAC_POW_FLAG_MASK, 1);
- break;
- }
+/**
+ * aic326x_hp_event: - To handle headphone related task before and after
+ * headphone powrup and power down
+ * @w: pointer variable to dapm_widget
+ * @kcontrol: mixer control
+ * @event: event element information
+ *
+ * Returns 0 for success.
+ */
+static int aic326x_hp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int reg_mask = 0;
+ int ret_wbits = 0;
+
+ if (w->shift == 1)
+ reg_mask = AIC3262_HPL_POWER_MASK;
+ if (w->shift == 0)
+ reg_mask = AIC3262_HPR_POWER_MASK;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ ret_wbits = aic3262_wait_bits(w->codec->control_data,
+ AIC3262_HP_FLAG, reg_mask,
+ reg_mask, TIME_DELAY,
+ DELAY_COUNTER);
+ if (!ret_wbits) {
+ dev_err(w->codec->dev, "HP POST_PMU timedout\n");
+ return -1;
+ }
break;
- default:
- printk("%s:unknown arguement\n", __func__);
- break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret_wbits = aic3262_wait_bits(w->codec->control_data,
+ AIC3262_HP_FLAG, reg_mask, 0,
+ TIME_DELAY, DELAY_COUNTER);
+ if (!ret_wbits) {
+ dev_err(w->codec->dev, "HP POST_PMD timedout\n");
+ return -1;
}
- if(ret)
- printk("%s: power %s %s failure", __func__, left_right?"right":"left", on_off?"on":"off");
- return ret;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
}
-int poll_adc(struct snd_soc_codec *codec, int left_right, int on_off)
-{
- int ret = 0;
+/**
+ *aic326x_dac_event: Headset popup reduction and powering up dsps together
+ * when they are in sync mode
+ * @w: pointer variable to dapm_widget
+ * @kcontrol: pointer to sound control
+ * @event: event element information
+ *
+ * Returns 0 for success.
+ */
+static int aic326x_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int reg_mask = 0;
+ int ret_wbits = 0;
+ int run_state_mask;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(w->codec);
+ int sync_needed = 0, non_sync_state = 0;
+ int other_dsp = 0, run_state = 0;
+
+ if (w->shift == 7) {
+ reg_mask = AIC3262_LDAC_POWER_MASK;
+ run_state_mask = AIC3262_COPS_MDSP_D_L;
+ }
+ if (w->shift == 6) {
+ reg_mask = AIC3262_RDAC_POWER_MASK;
+ run_state_mask = AIC3262_COPS_MDSP_D_R;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+
+ ret_wbits = aic3262_wait_bits(w->codec->control_data,
+ AIC3262_DAC_FLAG, reg_mask,
+ reg_mask, TIME_DELAY,
+ DELAY_COUNTER);
+
+ sync_needed = SYNC_STATE(aic3262);
+ non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate);
+ other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_A;
+
+ if (sync_needed && non_sync_state && other_dsp) {
+ run_state = get_runstate(aic3262->codec->control_data);
+ aic3262_dsp_pwrdwn_status(aic3262);
+ aic3262_dsp_pwrup(aic3262, run_state);
+ }
+ aic3262->dsp_runstate |= run_state_mask;
- aic3262_change_page(codec, 0);
- aic3262_change_book(codec, 0);
+ if (!ret_wbits) {
+ dev_err(w->codec->dev, "DAC POST_PMU timedout\n");
+ return -1;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
- switch(on_off) {
+ ret_wbits = aic3262_wait_bits(w->codec->control_data,
+ AIC3262_DAC_FLAG, reg_mask, 0,
+ TIME_DELAY, DELAY_COUNTER);
- case 0:/*power off polling*/
- /*DAC power polling logic*/
- switch(left_right) {
- case 0: /*left dac polling*/
- ret = polling_loop(codec, ADC_FLAG_R1, LADC_POW_FLAG_MASK, 0);
- break;
- case 1:/*right dac polling*/
- ret = polling_loop(codec, ADC_FLAG_R1, RADC_POW_FLAG_MASK, 0);
- break;
- }
- break;
- case 1:/*power on polling*/
- /*DAC power polling logic*/
- switch(left_right) {
- case 0: /*left dac polling*/
- ret = polling_loop(codec, ADC_FLAG_R1, LADC_POW_FLAG_MASK, 1);
- break;
- case 1:/*right dac polling*/
- ret = polling_loop(codec, ADC_FLAG_R1, RADC_POW_FLAG_MASK, 1);
- break;
+ aic3262->dsp_runstate = (aic3262->dsp_runstate &
+ ~run_state_mask);
+ if (!ret_wbits) {
+ dev_err(w->codec->dev, "DAC POST_PMD timedout\n");
+ return -1;
}
- break;
- default:
- printk("%s:unknown arguement\n", __func__);
- break;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
}
+ return 0;
+}
- if(ret)
- printk("%s: power %s %s failure", __func__, left_right?"right":"left", on_off?"on":"off");
- return ret;
+/**
+ * aic326x_spk_event: Speaker related task before and after
+ * headphone powrup and power down$
+ * @w: pointer variable to dapm_widget,
+ * @kcontrolr: pointer variable to sound control,
+ * @event: integer to event,
+ *
+ * Return value: 0 for success
+ */
+static int aic326x_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int reg_mask;
+
+ if (w->shift == 1)
+ reg_mask = AIC3262_SPKL_POWER_MASK;
+ if (w->shift == 0)
+ reg_mask = AIC3262_SPKR_POWER_MASK;
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ mdelay(1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ mdelay(1);
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
}
-static int slave_dac_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+/**$
+ * pll_power_on_event: provide delay after widget power up
+ * @w: pointer variable to dapm_widget,
+ * @kcontrolr: pointer variable to sound control,
+ * @event: integer to event,
+ *
+ * Return value: 0 for success
+ */
+static int pll_power_on_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ if (event == SND_SOC_DAPM_POST_PMU)
+ mdelay(10);
+ return 0;
+}
+/**
+ * aic3262_set_mode_get: To get different mode of Firmware through tinymix
+ * @kcontrolr: pointer to sound control,
+ * ucontrol: pointer to control element value,
+ *
+ * Return value: 0 for success
+ */
+static int aic3262_set_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct aic3262_priv *priv_ds = snd_soc_codec_get_drvdata(codec);
- if (event & SND_SOC_DAPM_POST_PMU) {
- /* Poll for DAC Power-up first */
- poll_dac(codec, 0, 1);
- poll_dac(codec, 1, 1);
- }
+ ucontrol->value.integer.value[0] = ((priv_ds->cfw_p->cur_mode << 8)
+ | priv_ds->cfw_p->cur_cfg);
- if (event & SND_SOC_DAPM_POST_PMD) {
- poll_dac(codec, 0, 0);
- poll_dac(codec, 1, 0);
- }
return 0;
}
-
-static int slave_adc_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-
+/**
+ * aic3262_set_mode_put: To set different mode of Firmware through tinymix
+ * @kcontrolr: pointer to sound control,
+ * ucontrol: pointer to control element value,
+ *
+ * Return value: 0 for success
+ */
+static int aic3262_set_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct aic3262_priv *priv_ds = snd_soc_codec_get_drvdata(codec);
- if (event & SND_SOC_DAPM_POST_PMU) {
+ int next_mode = 0, next_cfg = 0;
+ int ret = 0;
- /* Poll for ADC Power-up first */
- poll_adc(codec, 0, 1);
- poll_adc(codec, 1, 1);
- }
+ next_mode = (ucontrol->value.integer.value[0] >> 8);
+ next_cfg = (ucontrol->value.integer.value[0]) & 0xFF;
+ if (priv_ds == NULL)
+ dev_err(codec->dev, "failed to load firmware\n");
+ else
+ ret = aic3xxx_cfw_setmode_cfg(priv_ds->cfw_p,
+ next_mode, next_cfg);
+ return ret;
+}
- if (event & SND_SOC_DAPM_POST_PMD) {
- poll_adc(codec, 0, 0);
- poll_adc(codec, 1, 0);
+/**
+ * aic326x_adc_dsp_event: To get DSP run state to perform synchronization
+ * @w: pointer variable to dapm_widget
+ * @kcontrol: pointer to sound control
+ * @event: event element information
+ *
+ * Returns 0 for success.
+ */
+static int aic326x_adc_dsp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int run_state = 0;
+ int non_sync_state = 0, sync_needed = 0;
+ int other_dsp = 0;
+ int run_state_mask = 0;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(w->codec);
+ int reg_mask = 0;
+ int ret_wbits = 0;
+
+ if (w->shift == 7) {
+ reg_mask = AIC3262_LADC_POWER_MASK;
+ run_state_mask = AIC3262_COPS_MDSP_A_L;
+ }
+ if (w->shift == 6) {
+ reg_mask = AIC3262_RADC_POWER_MASK;
+ run_state_mask = AIC3262_COPS_MDSP_A_R;
+ }
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ ret_wbits = aic3262_wait_bits(w->codec->control_data,
+ AIC3262_ADC_FLAG, reg_mask,
+ reg_mask, TIME_DELAY,
+ DELAY_COUNTER);
+ sync_needed = SYNC_STATE(aic3262);
+ non_sync_state = DSP_NON_SYNC_MODE(aic3262->dsp_runstate);
+ other_dsp = aic3262->dsp_runstate & AIC3262_COPS_MDSP_D;
+ if (sync_needed && non_sync_state && other_dsp) {
+ run_state = get_runstate(aic3262->codec->control_data);
+ aic3262_dsp_pwrdwn_status(aic3262);
+ aic3262_dsp_pwrup(aic3262, run_state);
+ }
+ aic3262->dsp_runstate |= run_state_mask;
+ if (!ret_wbits) {
+ dev_err(w->codec->dev, "ADC POST_PMU timedout\n");
+ return -1;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret_wbits = aic3262_wait_bits(w->codec->control_data,
+ AIC3262_ADC_FLAG, reg_mask, 0,
+ TIME_DELAY, DELAY_COUNTER);
+ aic3262->dsp_runstate = (aic3262->dsp_runstate &
+ ~run_state_mask);
+ if (!ret_wbits) {
+ dev_err(w->codec->dev, "ADC POST_PMD timedout\n");
+ return -1;
+ }
+ break;
+ default:
+ BUG();
+ return -EINVAL;
}
-
return 0;
}
static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = {
- /* TODO: Can we switch these off ? */
- SND_SOC_DAPM_AIF_IN("ASI1IN", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_IN("ASI2IN", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_IN("ASI3IN", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0),
-
+ SND_SOC_DAPM_AIF_IN("DIN1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DIN2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("DIN3", "ASI3 Playback", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_DAC_E("Left DAC", NULL, PASI_DAC_DP_SETUP, 7, 0,
- slave_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD |
- SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_DAC_E("Right DAC", NULL, PASI_DAC_DP_SETUP, 6, 0,
- slave_dac_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD |
- SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_DAC_E("Left DAC", NULL, AIC3262_PASI_DAC_DP_SETUP, 7, 0,
+ aic326x_dac_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Right DAC", NULL, AIC3262_PASI_DAC_DP_SETUP, 6, 0,
+ aic326x_dac_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
/* dapm widget (path domain) for HPL Output Mixer */
SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0,
- &hpl_output_mixer_controls[0],
- ARRAY_SIZE(hpl_output_mixer_controls)),
+ &hpl_output_mixer_controls[0],
+ ARRAY_SIZE(hpl_output_mixer_controls)),
/* dapm widget (path domain) for HPR Output Mixer */
SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0,
- &hpr_output_mixer_controls[0],
- ARRAY_SIZE(hpr_output_mixer_controls)),
+ &hpr_output_mixer_controls[0],
+ ARRAY_SIZE(hpr_output_mixer_controls)),
- SND_SOC_DAPM_PGA_E("HPL Driver", HP_AMP_CNTL_R1, 1, 0, NULL, 0,
- aic326x_hp_event, SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_PGA_E("HPR Driver", HP_AMP_CNTL_R1, 0, 0, NULL, 0,
- aic326x_hp_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("HPL Driver", AIC3262_HP_AMP_CNTL_R1,
+ 1, 0, NULL, 0, aic326x_hp_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPR Driver", AIC3262_HP_AMP_CNTL_R1,
+ 0, 0, NULL, 0, aic326x_hp_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
/* dapm widget (path domain) for LOL Output Mixer */
SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0,
- &lol_output_mixer_controls[0],
- ARRAY_SIZE(lol_output_mixer_controls)),
+ &lol_output_mixer_controls[0],
+ ARRAY_SIZE(lol_output_mixer_controls)),
/* dapm widget (path domain) for LOR Output Mixer mixer */
SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0,
- &lor_output_mixer_controls[0],
- ARRAY_SIZE(lor_output_mixer_controls)),
+ &lor_output_mixer_controls[0],
+ ARRAY_SIZE(lor_output_mixer_controls)),
- SND_SOC_DAPM_PGA("LOL Driver", LINE_AMP_CNTL_R1, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("LOR Driver", LINE_AMP_CNTL_R1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LOL Driver", AIC3262_LINE_AMP_CNTL_R1,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("LOR Driver", AIC3262_LINE_AMP_CNTL_R1,
+ 0, 0, NULL, 0),
/* dapm widget (path domain) for SPKL Output Mixer */
SND_SOC_DAPM_MIXER("SPKL Output Mixer", SND_SOC_NOPM, 0, 0,
- &spkl_output_mixer_controls[0],
- ARRAY_SIZE(spkl_output_mixer_controls)),
+ &spkl_output_mixer_controls[0],
+ ARRAY_SIZE(spkl_output_mixer_controls)),
/* dapm widget (path domain) for SPKR Output Mixer */
SND_SOC_DAPM_MIXER("SPKR Output Mixer", SND_SOC_NOPM, 0, 0,
- &spkr_output_mixer_controls[0],
- ARRAY_SIZE(spkr_output_mixer_controls)),
+ &spkr_output_mixer_controls[0],
+ ARRAY_SIZE(spkr_output_mixer_controls)),
- SND_SOC_DAPM_PGA("SPKL Driver", SPK_AMP_CNTL_R1, 1, 0, NULL, 0),
- SND_SOC_DAPM_PGA("SPKR Driver", SPK_AMP_CNTL_R1, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA_E("SPKL Driver", AIC3262_SPK_AMP_CNTL_R1,
+ 1, 0, NULL, 0, aic326x_spk_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_E("SPKR Driver", AIC3262_SPK_AMP_CNTL_R1,
+ 0, 0, NULL, 0, aic326x_spk_event,
+ SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
/* dapm widget (path domain) for SPKR Output Mixer */
SND_SOC_DAPM_MIXER("REC Output Mixer", SND_SOC_NOPM, 0, 0,
- &rec_output_mixer_controls[0],
- ARRAY_SIZE(rec_output_mixer_controls)),
+ &rec_output_mixer_controls[0],
+ ARRAY_SIZE(rec_output_mixer_controls)),
- SND_SOC_DAPM_PGA("RECP Driver", REC_AMP_CNTL_R5, 7, 0, NULL, 0),
- SND_SOC_DAPM_PGA("RECM Driver", REC_AMP_CNTL_R5, 6, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RECP Driver", AIC3262_REC_AMP_CNTL_R5,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("RECM Driver", AIC3262_REC_AMP_CNTL_R5,
+ 6, 0, NULL, 0),
SND_SOC_DAPM_MUX("ASI1LIN Route",
- SND_SOC_NOPM, 0, 0, &asi1lin_control),
+ SND_SOC_NOPM, 0, 0, &asi1lin_control),
SND_SOC_DAPM_MUX("ASI1RIN Route",
- SND_SOC_NOPM, 0, 0, &asi1rin_control),
+ SND_SOC_NOPM, 0, 0, &asi1rin_control),
SND_SOC_DAPM_MUX("ASI2LIN Route",
- SND_SOC_NOPM, 0, 0, &asi2lin_control),
+ SND_SOC_NOPM, 0, 0, &asi2lin_control),
SND_SOC_DAPM_MUX("ASI2RIN Route",
- SND_SOC_NOPM, 0, 0, &asi2rin_control),
+ SND_SOC_NOPM, 0, 0, &asi2rin_control),
SND_SOC_DAPM_MUX("ASI3LIN Route",
- SND_SOC_NOPM, 0, 0, &asi3lin_control),
+ SND_SOC_NOPM, 0, 0, &asi3lin_control),
SND_SOC_DAPM_MUX("ASI3RIN Route",
- SND_SOC_NOPM, 0, 0, &asi3rin_control),
+ SND_SOC_NOPM, 0, 0, &asi3rin_control),
SND_SOC_DAPM_PGA("ASI1LIN", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASI1RIN", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -3030,14 +1078,6 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = {
SND_SOC_DAPM_PGA("ASI2RIN", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASI3LIN", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASI3RIN", SND_SOC_NOPM, 0, 0, NULL, 0),
-
- SND_SOC_DAPM_PGA("ASI1LOUT", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ASI1ROUT", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ASI2LOUT", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ASI2ROUT", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ASI3LOUT", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("ASI3ROUT", SND_SOC_NOPM, 0, 0, NULL, 0),
-
SND_SOC_DAPM_PGA("ASI1MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASI2MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASI3MonoMixIN", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -3046,13 +1086,15 @@ static const struct snd_soc_dapm_widget aic3262_dapm_widgets[] = {
SND_SOC_DAPM_PGA("ASI2IN Port", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ASI3IN Port", SND_SOC_NOPM, 0, 0, NULL, 0),
-
SND_SOC_DAPM_MUX("DAC MiniDSP IN1 Route",
- SND_SOC_NOPM, 0, 0, &dacminidspin1_control),
-SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route",
- SND_SOC_NOPM, 0, 0, &dacminidspin2_control),
+ SND_SOC_NOPM, 0, 0, &dacminidspin1_control),
+ SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route",
+ SND_SOC_NOPM, 0, 0, &dacminidspin2_control),
SND_SOC_DAPM_MUX("DAC MiniDSP IN3 Route",
- SND_SOC_NOPM, 0, 0, &dacminidspin3_control),
+ SND_SOC_NOPM, 0, 0, &dacminidspin3_control),
+
+ SND_SOC_DAPM_VIRT_MUX("ADC DAC Route",
+ SND_SOC_NOPM, 0, 0, &adcdacroute_control),
SND_SOC_DAPM_PGA("CM", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("CM1L", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -3061,59 +1103,74 @@ SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route",
SND_SOC_DAPM_PGA("CM2R", SND_SOC_NOPM, 0, 0, NULL, 0),
/* TODO: Can we switch these off ? */
- SND_SOC_DAPM_AIF_OUT("ASI1OUT","ASI1 Capture", 0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_OUT("ASI2OUT", "ASI2 Capture",0, SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_AIF_OUT("ASI3OUT", "ASI3 Capture",0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DOUT1", "ASI1 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DOUT2", "ASI2 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DOUT3", "ASI3 Capture", 0, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MUX("DOUT1 Route",
+ SND_SOC_NOPM, 0, 0, &dout1_control),
+ SND_SOC_DAPM_MUX("DOUT2 Route",
+ SND_SOC_NOPM, 0, 0, &dout2_control),
+ SND_SOC_DAPM_MUX("DOUT3 Route",
+ SND_SOC_NOPM, 0, 0, &dout3_control),
+
+ SND_SOC_DAPM_PGA("ASI1OUT", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASI2OUT", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("ASI3OUT", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("ASI1OUT Route",
- SND_SOC_NOPM, 0, 0, &asi1out_control),
+ SND_SOC_NOPM, 0, 0, &asi1out_control),
SND_SOC_DAPM_MUX("ASI2OUT Route",
- SND_SOC_NOPM, 0, 0, &asi2out_control),
+ SND_SOC_NOPM, 0, 0, &asi2out_control),
SND_SOC_DAPM_MUX("ASI3OUT Route",
- SND_SOC_NOPM, 0, 0, &asi3out_control),
+ SND_SOC_NOPM, 0, 0, &asi3out_control),
- /* TODO: Will be used during MINIDSP programming */
+ /* TODO: Can we switch the ASI1 OUT1 off? */
/* TODO: Can we switch them off? */
SND_SOC_DAPM_PGA("ADC MiniDSP OUT1", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ADC MiniDSP OUT2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("ADC MiniDSP OUT3", SND_SOC_NOPM, 0, 0, NULL, 0),
+/* SND_SOC_DAPM_MUX("DMICDAT Input Route",
+ SND_SOC_NOPM, 0, 0, &dmicinput_control),*/
+ SND_SOC_DAPM_MUX("Left ADC Route", SND_SOC_NOPM, 0, 0, &adcl_mux),
+ SND_SOC_DAPM_MUX("Right ADC Route", SND_SOC_NOPM, 0, 0, &adcr_mux),
- SND_SOC_DAPM_ADC_E("Left ADC", NULL, ADC_CHANNEL_POW, 7, 0,
- slave_adc_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD |
- SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_ADC_E("Right ADC", NULL, ADC_CHANNEL_POW, 6, 0,
- slave_adc_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD |
- SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_ADC_E("Left ADC", NULL, AIC3262_ADC_CHANNEL_POW, 7, 0,
+ aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("Right ADC", NULL, AIC3262_ADC_CHANNEL_POW, 6, 0,
+ aic326x_adc_dsp_event, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA("Left MicPGA",MICL_PGA, 7, 1, NULL, 0),
- SND_SOC_DAPM_PGA("Right MicPGA",MICR_PGA, 7, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Left MicPGA", AIC3262_MICL_PGA, 7, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("Right MicPGA", AIC3262_MICR_PGA, 7, 1, NULL, 0),
- SND_SOC_DAPM_PGA("MAL PGA", MA_CNTL, 3, 0, NULL, 0),
- SND_SOC_DAPM_PGA("MAR PGA", MA_CNTL, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MAL PGA", AIC3262_MA_CNTL,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("MAR PGA", AIC3262_MA_CNTL,
+ 2, 0, NULL, 0),
-
- /* dapm widget for MAL PGA Mixer*/
+ /* dapm widget for MAL PGA Mixer */
SND_SOC_DAPM_MIXER("MAL PGA Mixer", SND_SOC_NOPM, 0, 0,
- &mal_pga_mixer_controls[0],
- ARRAY_SIZE(mal_pga_mixer_controls)),
+ &mal_pga_mixer_controls[0],
+ ARRAY_SIZE(mal_pga_mixer_controls)),
- /* dapm widget for MAR PGA Mixer*/
+ /* dapm widget for MAR PGA Mixer */
SND_SOC_DAPM_MIXER("MAR PGA Mixer", SND_SOC_NOPM, 0, 0,
- &mar_pga_mixer_controls[0],
- ARRAY_SIZE(mar_pga_mixer_controls)),
+ &mar_pga_mixer_controls[0],
+ ARRAY_SIZE(mar_pga_mixer_controls)),
- /* dapm widget for Left Input Mixer*/
+ /* dapm widget for Left Input Mixer */
SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0,
- &left_input_mixer_controls[0],
- ARRAY_SIZE(left_input_mixer_controls)),
+ &left_input_mixer_controls[0],
+ ARRAY_SIZE(left_input_mixer_controls)),
- /* dapm widget for Right Input Mixer*/
+ /* dapm widget for Right Input Mixer */
SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0,
- &right_input_mixer_controls[0],
- ARRAY_SIZE(right_input_mixer_controls)),
-
+ &right_input_mixer_controls[0],
+ ARRAY_SIZE(right_input_mixer_controls)),
SND_SOC_DAPM_OUTPUT("HPL"),
SND_SOC_DAPM_OUTPUT("HPR"),
@@ -3132,31 +1189,36 @@ SND_SOC_DAPM_MUX("DAC MiniDSP IN2 Route",
SND_SOC_DAPM_INPUT("IN2R"),
SND_SOC_DAPM_INPUT("IN3R"),
SND_SOC_DAPM_INPUT("IN4R"),
-
-
- SND_SOC_DAPM_MICBIAS("Mic Bias Ext", MIC_BIAS_CNTL, 6, 0),
- SND_SOC_DAPM_MICBIAS("Mic Bias Int", MIC_BIAS_CNTL, 2, 0),
-
- SND_SOC_DAPM_SUPPLY("PLLCLK",PLL_PR_POW_REG,7,0,pll_power_on_event,
- SND_SOC_DAPM_POST_PMU),
- SND_SOC_DAPM_SUPPLY("DACCLK",NDAC_DIV_POW_REG,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN",SND_SOC_NOPM,0,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK",MDAC_DIV_POW_REG,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ADCCLK",NADC_DIV_POW_REG,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK",MADC_DIV_POW_REG,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ASI1_BCLK",ASI1_BCLK_N,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ASI1_WCLK",ASI1_WCLK_N,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ASI2_BCLK",ASI2_BCLK_N,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ASI2_WCLK",ASI2_WCLK_N,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ASI3_BCLK",ASI3_BCLK_N,7,0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("ASI3_WCLK",ASI3_WCLK_N,7,0, NULL, 0),
+ SND_SOC_DAPM_INPUT("Left DMIC"),
+ SND_SOC_DAPM_INPUT("Right DMIC"),
+
+ SND_SOC_DAPM_MICBIAS("Mic Bias Ext", AIC3262_MIC_BIAS_CNTL, 6, 0),
+ SND_SOC_DAPM_MICBIAS("Mic Bias Int", AIC3262_MIC_BIAS_CNTL, 2, 0),
+
+ SND_SOC_DAPM_SUPPLY("PLLCLK", AIC3262_PLL_PR_POW_REG, 7, 0,
+ pll_power_on_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("DACCLK", AIC3262_NDAC_DIV_POW_REG, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_MOD_CLK", AIC3262_MDAC_DIV_POW_REG,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADCCLK", AIC3262_NADC_DIV_POW_REG, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_MOD_CLK", AIC3262_MADC_DIV_POW_REG,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASI1_BCLK", AIC3262_ASI1_BCLK_N, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASI1_WCLK", AIC3262_ASI1_WCLK_N, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASI2_BCLK", AIC3262_ASI2_BCLK_N, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASI2_WCLK", AIC3262_ASI2_WCLK_N, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASI3_BCLK", AIC3262_ASI3_BCLK_N, 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("ASI3_WCLK", AIC3262_ASI3_WCLK_N, 7, 0, NULL, 0),
SND_SOC_DAPM_MUX("ASI1_BCLK Route",
- SND_SOC_NOPM, 0, 0, &asi1bclk_control),
- SND_SOC_DAPM_MUX("ASI2_BCLK Route", SND_SOC_NOPM, 0, 0, &asi2bclk_control),
- SND_SOC_DAPM_MUX("ASI3_BCLK Route", SND_SOC_NOPM, 0, 0, &asi3bclk_control),
+ SND_SOC_NOPM, 0, 0, &asi1bclk_control),
+ SND_SOC_DAPM_MUX("ASI2_BCLK Route",
+ SND_SOC_NOPM, 0, 0, &asi2bclk_control),
+ SND_SOC_DAPM_MUX("ASI3_BCLK Route",
+ SND_SOC_NOPM, 0, 0, &asi3bclk_control),
};
-static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={
+static const struct snd_soc_dapm_route aic3262_dapm_routes[] = {
/* TODO: Do we need only DACCLK for ASIIN's and ADCCLK for ASIOUT??? */
/* Clock portion */
{"CODEC_CLK_IN", NULL, "PLLCLK"},
@@ -3164,185 +1226,179 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={
{"ADCCLK", NULL, "CODEC_CLK_IN"},
{"DAC_MOD_CLK", NULL, "DACCLK"},
#ifdef AIC3262_SYNC_MODE
- {"ADC_MOD_CLK", NULL,"DACCLK"},
+ {"ADC_MOD_CLK", NULL, "DACCLK"},
#else
{"ADC_MOD_CLK", NULL, "ADCCLK"},
#endif
- {"ASI1_BCLK Route","DAC_CLK","DACCLK"},
- {"ASI1_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"},
- {"ASI1_BCLK Route","ADC_CLK","ADCCLK"},
- {"ASI1_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"},
+ {"ASI1_BCLK Route", "DAC_CLK", "DACCLK"},
+ {"ASI1_BCLK Route", "DAC_MOD_CLK", "DAC_MOD_CLK"},
+ {"ASI1_BCLK Route", "ADC_CLK", "ADCCLK"},
+ {"ASI1_BCLK Route", "ADC_MOD_CLK", "ADC_MOD_CLK"},
- {"ASI2_BCLK Route","DAC_CLK","DACCLK"},
- {"ASI2_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"},
- {"ASI2_BCLK Route","ADC_CLK","ADCCLK"},
- {"ASI2_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"},
+ {"ASI2_BCLK Route", "DAC_CLK", "DACCLK"},
+ {"ASI2_BCLK Route", "DAC_MOD_CLK", "DAC_MOD_CLK"},
+ {"ASI2_BCLK Route", "ADC_CLK", "ADCCLK"},
+ {"ASI2_BCLK Route", "ADC_MOD_CLK", "ADC_MOD_CLK"},
- {"ASI3_BCLK Route","DAC_CLK","DACCLK"},
- {"ASI3_BCLK Route","DAC_MOD_CLK","DAC_MOD_CLK"},
- {"ASI3_BCLK Route","ADC_CLK","ADCCLK"},
- {"ASI3_BCLK Route","ADC_MOD_CLK","ADC_MOD_CLK"},
+ {"ASI3_BCLK Route", "DAC_CLK", "DACCLK"},
+ {"ASI3_BCLK Route", "DAC_MOD_CLK", "DAC_MOD_CLK"},
+ {"ASI3_BCLK Route", "ADC_CLK", "ADCCLK"},
+ {"ASI3_BCLK Route", "ADC_MOD_CLK", "ADC_MOD_CLK"},
{"ASI1_BCLK", NULL, "ASI1_BCLK Route"},
{"ASI2_BCLK", NULL, "ASI2_BCLK Route"},
{"ASI3_BCLK", NULL, "ASI3_BCLK Route"},
-
- {"ASI1IN", NULL , "PLLCLK"},
- {"ASI1IN", NULL , "DACCLK"},
- {"ASI1IN", NULL , "ADCCLK"},
- {"ASI1IN", NULL , "DAC_MOD_CLK"},
- {"ASI1IN", NULL , "ADC_MOD_CLK"},
-
- {"ASI1OUT", NULL , "PLLCLK"},
- {"ASI1OUT", NULL , "DACCLK"},
- {"ASI1OUT", NULL , "ADCCLK"},
- {"ASI1OUT", NULL , "DAC_MOD_CLK"},
- {"ASI1OUT", NULL , "ADC_MOD_CLK"},
+ {"DIN1", NULL, "PLLCLK"},
+ {"DIN1", NULL, "DACCLK"},
+ {"DIN1", NULL, "ADCCLK"},
+ {"DIN1", NULL, "DAC_MOD_CLK"},
+ {"DIN1", NULL, "ADC_MOD_CLK"},
+
+ {"DOUT1", NULL, "PLLCLK"},
+ {"DOUT1", NULL, "DACCLK"},
+ {"DOUT1", NULL, "ADCCLK"},
+ {"DOUT1", NULL, "DAC_MOD_CLK"},
+ {"DOUT1", NULL, "ADC_MOD_CLK"},
#ifdef AIC3262_ASI1_MASTER
- {"ASI1IN", NULL , "ASI1_BCLK"},
- {"ASI1OUT", NULL , "ASI1_BCLK"},
- {"ASI1IN", NULL , "ASI1_WCLK"},
- {"ASI1OUT", NULL , "ASI1_WCLK"},
+ {"DIN1", NULL, "ASI1_BCLK"},
+ {"DOUT1", NULL, "ASI1_BCLK"},
+ {"DIN1", NULL, "ASI1_WCLK"},
+ {"DOUT1", NULL, "ASI1_WCLK"},
#else
#endif
-
- {"ASI2IN", NULL , "PLLCLK"},
- {"ASI2IN", NULL , "DACCLK"},
- {"ASI2IN", NULL , "ADCCLK"},
- {"ASI2IN", NULL , "DAC_MOD_CLK"},
- {"ASI2IN", NULL , "ADC_MOD_CLK"},
-
- {"ASI2OUT", NULL , "PLLCLK"},
- {"ASI2OUT", NULL , "DACCLK"},
- {"ASI2OUT", NULL , "ADCCLK"},
- {"ASI2OUT", NULL , "DAC_MOD_CLK"},
- {"ASI2OUT", NULL , "ADC_MOD_CLK"},
+ {"DIN2", NULL, "PLLCLK"},
+ {"DIN2", NULL, "DACCLK"},
+ {"DIN2", NULL, "ADCCLK"},
+ {"DIN2", NULL, "DAC_MOD_CLK"},
+ {"DIN2", NULL, "ADC_MOD_CLK"},
+
+ {"DOUT2", NULL, "PLLCLK"},
+ {"DOUT2", NULL, "DACCLK"},
+ {"DOUT2", NULL, "ADCCLK"},
+ {"DOUT2", NULL, "DAC_MOD_CLK"},
+ {"DOUT2", NULL, "ADC_MOD_CLK"},
#ifdef AIC3262_ASI2_MASTER
- {"ASI2IN", NULL , "ASI2_BCLK"},
- {"ASI2OUT", NULL , "ASI2_BCLK"},
- {"ASI2IN", NULL , "ASI2_WCLK"},
- {"ASI2OUT", NULL , "ASI2_WCLK"},
+ {"DIN2", NULL, "ASI2_BCLK"},
+ {"DOUT2", NULL, "ASI2_BCLK"},
+ {"DIN2", NULL, "ASI2_WCLK"},
+ {"DOUT2", NULL, "ASI2_WCLK"},
#else
#endif
- {"ASI3IN", NULL , "PLLCLK"},
- {"ASI3IN", NULL , "DACCLK"},
- {"ASI3IN", NULL , "ADCCLK"},
- {"ASI3IN", NULL , "DAC_MOD_CLK"},
- {"ASI3IN", NULL , "ADC_MOD_CLK"},
-
-
- {"ASI3OUT", NULL , "PLLCLK"},
- {"ASI3OUT", NULL , "DACCLK"},
- {"ASI3OUT", NULL , "ADCCLK"},
- {"ASI3OUT", NULL , "DAC_MOD_CLK"},
- {"ASI3OUT", NULL , "ADC_MOD_CLK"},
+ {"DIN3", NULL, "PLLCLK"},
+ {"DIN3", NULL, "DACCLK"},
+ {"DIN3", NULL, "ADCCLK"},
+ {"DIN3", NULL, "DAC_MOD_CLK"},
+ {"DIN3", NULL, "ADC_MOD_CLK"},
+
+ {"DOUT3", NULL, "PLLCLK"},
+ {"DOUT3", NULL, "DACCLK"},
+ {"DOUT3", NULL, "ADCCLK"},
+ {"DOUT3", NULL, "DAC_MOD_CLK"},
+ {"DOUT3", NULL, "ADC_MOD_CLK"},
#ifdef AIC3262_ASI3_MASTER
- {"ASI3IN", NULL , "ASI3_BCLK"},
- {"ASI3OUT", NULL , "ASI3_BCLK"},
- {"ASI3IN", NULL , "ASI3_WCLK"},
- {"ASI3OUT", NULL , "ASI3_WCLK"},
+ {"DIN3", NULL, "ASI3_BCLK"},
+ {"DOUT3", NULL, "ASI3_BCLK"},
+ {"DIN3", NULL, "ASI3_WCLK"},
+ {"DOUT3", NULL, "ASI3_WCLK"},
#else
-#endif
-
-/* Playback (DAC) Portion */
- {"HPL Output Mixer","LDAC Switch","Left DAC"},
- {"HPL Output Mixer","MAL Switch","MAL PGA"},
- {"HPL Output Mixer","LOL-B1 Volume","LOL"},
- {"HPR Output Mixer","LOR-B1 Volume","LOR"},
- {"HPR Output Mixer","LDAC Switch","Left DAC"},
- {"HPR Output Mixer","RDAC Switch","Right DAC"},
- {"HPR Output Mixer","MAR Switch","MAR PGA"},
-
- {"HPL Driver",NULL,"HPL Output Mixer"},
- {"HPR Driver",NULL,"HPR Output Mixer"},
-
- {"HPL",NULL,"HPL Driver"},
- {"HPR",NULL,"HPR Driver"},
+#endif
+ /* Playback (DAC) Portion */
+ {"HPL Output Mixer", "LDAC Switch", "Left DAC"},
+ {"HPL Output Mixer", "MAL Switch", "MAL PGA"},
+ {"HPL Output Mixer", "LOL-B1 Volume", "LOL"},
- {"LOL Output Mixer","MAL Switch","MAL PGA"},
- {"LOL Output Mixer","IN1L-B Switch","IN1L"},
- {"LOL Output Mixer","LDAC Switch","Left DAC"},
- {"LOL Output Mixer","RDAC Switch","Right DAC"},
+ {"HPR Output Mixer", "LOR-B1 Volume", "LOR"},
+ {"HPR Output Mixer", "LDAC Switch", "Left DAC"},
+ {"HPR Output Mixer", "RDAC Switch", "Right DAC"},
+ {"HPR Output Mixer", "MAR Switch", "MAR PGA"},
- {"LOR Output Mixer","LOL Switch","LOL"},
- {"LOR Output Mixer","RDAC Switch","Right DAC"},
- {"LOR Output Mixer","MAR Switch","MAR PGA"},
- {"LOR Output Mixer","IN1R-B Switch","IN1R"},
+ {"HPL Driver", NULL, "HPL Output Mixer"},
+ {"HPR Driver", NULL, "HPR Output Mixer"},
- {"LOL Driver",NULL,"LOL Output Mixer"},
- {"LOR Driver",NULL,"LOR Output Mixer"},
+ {"HPL", NULL, "HPL Driver"},
+ {"HPR", NULL, "HPR Driver"},
- {"LOL",NULL,"LOL Driver"},
- {"LOR",NULL,"LOR Driver"},
+ {"LOL Output Mixer", "MAL Switch", "MAL PGA"},
+ {"LOL Output Mixer", "IN1L-B Switch", "IN1L"},
+ {"LOL Output Mixer", "LDAC Switch", "Left DAC"},
+ {"LOL Output Mixer", "RDAC Switch", "Right DAC"},
- {"REC Output Mixer","LOL-B2 Volume","LOL"},
- {"REC Output Mixer","IN1L Volume","IN1L"},
- {"REC Output Mixer","IN1R Volume","IN1R"},
- {"REC Output Mixer","LOR-B2 Volume","LOR"},
+ {"LOR Output Mixer", "LOL Switch", "LOL"},
+ {"LOR Output Mixer", "RDAC Switch", "Right DAC"},
+ {"LOR Output Mixer", "MAR Switch", "MAR PGA"},
+ {"LOR Output Mixer", "IN1R-B Switch", "IN1R"},
- {"RECP Driver",NULL,"REC Output Mixer"},
- {"RECM Driver",NULL,"REC Output Mixer"},
+ {"LOL Driver", NULL, "LOL Output Mixer"},
+ {"LOR Driver", NULL, "LOR Output Mixer"},
- {"RECP",NULL,"RECP Driver"},
- {"RECM",NULL,"RECM Driver"},
+ {"LOL", NULL, "LOL Driver"},
+ {"LOR", NULL, "LOR Driver"},
- {"SPKL Output Mixer","MAL Switch","MAL PGA"},
- {"SPKL Output Mixer","LOL Volume","LOL"},
- {"SPKL Output Mixer","SPR_IN Switch","SPKR Output Mixer"},
+ {"REC Output Mixer", "LOL-B2 Volume", "LOL"},
+ {"REC Output Mixer", "IN1L Volume", "IN1L"},
+ {"REC Output Mixer", "IN1R Volume", "IN1R"},
+ {"REC Output Mixer", "LOR-B2 Volume", "LOR"},
- {"SPKR Output Mixer", "LOR Volume","LOR"},
- {"SPKR Output Mixer", "MAR Switch","MAR PGA"},
+ {"RECP Driver", NULL, "REC Output Mixer"},
+ {"RECM Driver", NULL, "REC Output Mixer"},
+ {"RECP", NULL, "RECP Driver"},
+ {"RECM", NULL, "RECM Driver"},
- {"SPKL Driver",NULL,"SPKL Output Mixer"},
- {"SPKR Driver",NULL,"SPKR Output Mixer"},
+ {"SPKL Output Mixer", "MAL Switch", "MAL PGA"},
+ {"SPKL Output Mixer", "LOL Volume", "LOL"},
+ {"SPKL Output Mixer", "SPR_IN Switch", "SPKR Output Mixer"},
- {"SPKL",NULL,"SPKL Driver"},
- {"SPKR",NULL,"SPKR Driver"},
-/* ASI Input routing */
- {"ASI1LIN", NULL, "ASI1IN"},
- {"ASI1RIN", NULL, "ASI1IN"},
- {"ASI2LIN", NULL, "ASI2IN"},
- {"ASI2RIN", NULL, "ASI2IN"},
- {"ASI3LIN", NULL, "ASI3IN"},
- {"ASI3RIN", NULL, "ASI3IN"},
+ {"SPKR Output Mixer", "LOR Volume", "LOR"},
+ {"SPKR Output Mixer", "MAR Switch", "MAR PGA"},
- {"ASI1MonoMixIN", NULL, "ASI1IN"},
- {"ASI2MonoMixIN", NULL, "ASI2IN"},
- {"ASI3MonoMixIN", NULL, "ASI3IN"},
- {"ASI1LIN Route","ASI1 Left In","ASI1LIN"},
- {"ASI1LIN Route","ASI1 Right In","ASI1RIN"},
- {"ASI1LIN Route","ASI1 MonoMix In","ASI1MonoMixIN"},
+ {"SPKL Driver", NULL, "SPKL Output Mixer"},
+ {"SPKR Driver", NULL, "SPKR Output Mixer"},
- {"ASI1RIN Route", "ASI1 Right In","ASI1RIN"},
- {"ASI1RIN Route","ASI1 Left In","ASI1LIN"},
- {"ASI1RIN Route","ASI1 MonoMix In","ASI1MonoMixIN"},
+ {"SPKL", NULL, "SPKL Driver"},
+ {"SPKR", NULL, "SPKR Driver"},
+ /* ASI Input routing */
+ {"ASI1LIN", NULL, "DIN1"},
+ {"ASI1RIN", NULL, "DIN1"},
+ {"ASI1MonoMixIN", NULL, "DIN1"},
+ {"ASI2LIN", NULL, "DIN2"},
+ {"ASI2RIN", NULL, "DIN2"},
+ {"ASI2MonoMixIN", NULL, "DIN2"},
+ {"ASI3LIN", NULL, "DIN3"},
+ {"ASI3RIN", NULL, "DIN3"},
+ {"ASI3MonoMixIN", NULL, "DIN3"},
+ {"ASI1LIN Route", "ASI1 Left In", "ASI1LIN"},
+ {"ASI1LIN Route", "ASI1 Right In", "ASI1RIN"},
+ {"ASI1LIN Route", "ASI1 MonoMix In", "ASI1MonoMixIN"},
- {"ASI2LIN Route","ASI2 Left In","ASI2LIN"},
- {"ASI2LIN Route","ASI2 Right In","ASI2RIN"},
- {"ASI2LIN Route","ASI2 MonoMix In","ASI2MonoMixIN"},
+ {"ASI1RIN Route", "ASI1 Right In", "ASI1RIN"},
+ {"ASI1RIN Route", "ASI1 Left In", "ASI1LIN"},
+ {"ASI1RIN Route", "ASI1 MonoMix In", "ASI1MonoMixIN"},
- {"ASI2RIN Route","ASI2 Right In","ASI2RIN"},
- {"ASI2RIN Route","ASI2 Left In","ASI2LIN"},
- {"ASI2RIN Route","ASI2 MonoMix In","ASI2MonoMixIN"},
+ {"ASI2LIN Route", "ASI2 Left In", "ASI2LIN"},
+ {"ASI2LIN Route", "ASI2 Right In", "ASI2RIN"},
+ {"ASI2LIN Route", "ASI2 MonoMix In", "ASI2MonoMixIN"},
+ {"ASI2RIN Route", "ASI2 Right In", "ASI2RIN"},
+ {"ASI2RIN Route", "ASI2 Left In", "ASI2LIN"},
+ {"ASI2RIN Route", "ASI2 MonoMix In", "ASI2MonoMixIN"},
- {"ASI3LIN Route","ASI3 Left In","ASI3LIN"},
- {"ASI3LIN Route","ASI3 Right In","ASI3RIN"},
- {"ASI3LIN Route","ASI3 MonoMix In","ASI3MonoMixIN"},
+ {"ASI3LIN Route", "ASI3 Left In", "ASI3LIN"},
+ {"ASI3LIN Route", "ASI3 Right In", "ASI3RIN"},
+ {"ASI3LIN Route", "ASI3 MonoMix In", "ASI3MonoMixIN"},
- {"ASI3RIN Route","ASI3 Right In","ASI3RIN"},
- {"ASI3RIN Route","ASI3 Left In","ASI3LIN"},
- {"ASI3RIN Route","ASI3 MonoMix In","ASI3MonoMixIN"},
+ {"ASI3RIN Route", "ASI3 Right In", "ASI3RIN"},
+ {"ASI3RIN Route", "ASI3 Left In", "ASI3LIN"},
+ {"ASI3RIN Route", "ASI3 MonoMix In", "ASI3MonoMixIN"},
{"ASI1IN Port", NULL, "ASI1LIN Route"},
{"ASI1IN Port", NULL, "ASI1RIN Route"},
@@ -3351,83 +1407,94 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={
{"ASI3IN Port", NULL, "ASI3LIN Route"},
{"ASI3IN Port", NULL, "ASI3RIN Route"},
- {"DAC MiniDSP IN1 Route", "ASI1 In","ASI1IN Port"},
- {"DAC MiniDSP IN1 Route","ASI2 In","ASI2IN Port"},
- {"DAC MiniDSP IN1 Route","ASI3 In","ASI3IN Port"},
- {"DAC MiniDSP IN1 Route","ADC MiniDSP Out","ADC MiniDSP OUT1"},
+ {"DAC MiniDSP IN1 Route", "ASI1 In", "ASI1IN Port"},
+ {"DAC MiniDSP IN1 Route", "ASI2 In", "ASI2IN Port"},
+ {"DAC MiniDSP IN1 Route", "ASI3 In", "ASI3IN Port"},
+ {"DAC MiniDSP IN1 Route", "ADC MiniDSP Out", "ADC MiniDSP OUT1"},
- {"DAC MiniDSP IN2 Route","ASI1 In","ASI1IN Port"},
- {"DAC MiniDSP IN2 Route","ASI2 In","ASI2IN Port"},
- {"DAC MiniDSP IN2 Route","ASI3 In","ASI3IN Port"},
+ {"DAC MiniDSP IN2 Route", "ASI1 In", "ASI1IN Port"},
+ {"DAC MiniDSP IN2 Route", "ASI2 In", "ASI2IN Port"},
+ {"DAC MiniDSP IN2 Route", "ASI3 In", "ASI3IN Port"},
- {"DAC MiniDSP IN3 Route","ASI1 In","ASI1IN Port"},
- {"DAC MiniDSP IN3 Route","ASI2 In","ASI2IN Port"},
- {"DAC MiniDSP IN3 Route","ASI3 In","ASI3IN Port"},
+ {"DAC MiniDSP IN3 Route", "ASI1 In", "ASI1IN Port"},
+ {"DAC MiniDSP IN3 Route", "ASI2 In", "ASI2IN Port"},
+ {"DAC MiniDSP IN3 Route", "ASI3 In", "ASI3IN Port"},
{"Left DAC", "NULL", "DAC MiniDSP IN1 Route"},
{"Right DAC", "NULL", "DAC MiniDSP IN1 Route"},
+ {"Left DAC", "NULL", "DAC MiniDSP IN2 Route"},
+ {"Right DAC", "NULL", "DAC MiniDSP IN2 Route"},
+ {"Left DAC", "NULL", "DAC MiniDSP IN3 Route"},
+ {"Right DAC", "NULL", "DAC MiniDSP IN3 Route"},
- {"Left DAC", "NULL","DAC MiniDSP IN2 Route"},
- {"Right DAC", "NULL","DAC MiniDSP IN2 Route"},
-
- {"Left DAC", "NULL","DAC MiniDSP IN3 Route"},
- {"Right DAC", "NULL","DAC MiniDSP IN3 Route"},
-
-
-/* Mixer Amplifier */
+ /* Mixer Amplifier */
- {"MAL PGA Mixer", "IN1L Switch","IN1L"},
- {"MAL PGA Mixer", "Left MicPGA Volume","Left MicPGA"},
+ {"MAL PGA Mixer", "IN1L Switch", "IN1L"},
+ {"MAL PGA Mixer", "Left MicPGA Volume", "Left MicPGA"},
{"MAL PGA", NULL, "MAL PGA Mixer"},
- {"MAR PGA Mixer", "IN1R Switch","IN1R"},
- {"MAR PGA Mixer", "Right MicPGA Volume","Right MicPGA"},
+ {"MAR PGA Mixer", "IN1R Switch", "IN1R"},
+ {"MAR PGA Mixer", "Right MicPGA Volume", "Right MicPGA"},
{"MAR PGA", NULL, "MAR PGA Mixer"},
-/* Capture (ADC) portions */
+ /* Virtual connection between DAC and ADC for miniDSP IPC */
+ {"ADC DAC Route", "On", "Left ADC"},
+ {"ADC DAC Route", "On", "Right ADC"},
+
+ {"Left DAC", NULL, "ADC DAC Route"},
+ {"Right DAC", NULL, "ADC DAC Route"},
+
+ /* Capture (ADC) portions */
/* Left Positive PGA input */
- {"Left Input Mixer","IN1L Switch","IN1L"},
- {"Left Input Mixer","IN2L Switch","IN2L"},
- {"Left Input Mixer","IN3L Switch","IN3L"},
- {"Left Input Mixer","IN4L Switch","IN4L"},
- {"Left Input Mixer","IN1R Switch","IN1R"},
+ {"Left Input Mixer", "IN1L Switch", "IN1L"},
+ {"Left Input Mixer", "IN2L Switch", "IN2L"},
+ {"Left Input Mixer", "IN3L Switch", "IN3L"},
+ {"Left Input Mixer", "IN4L Switch", "IN4L"},
+ {"Left Input Mixer", "IN1R Switch", "IN1R"},
/* Left Negative PGA input */
- {"Left Input Mixer","IN2R Switch","IN2R"},
- {"Left Input Mixer","IN3R Switch","IN3R"},
- {"Left Input Mixer","IN4R Switch","IN4R"},
- {"Left Input Mixer","CM2L Switch","CM2L"},
- {"Left Input Mixer","CM1L Switch","CM1L"},
+ {"Left Input Mixer", "IN2R Switch", "IN2R"},
+ {"Left Input Mixer", "IN3R Switch", "IN3R"},
+ {"Left Input Mixer", "IN4R Switch", "IN4R"},
+ {"Left Input Mixer", "CM2L Switch", "CM2L"},
+ {"Left Input Mixer", "CM1L Switch", "CM1L"},
- /* Right Positive PGA Input */
- {"Right Input Mixer","IN1R Switch","IN1R"},
- {"Right Input Mixer","IN2R Switch","IN2R"},
- {"Right Input Mixer","IN3R Switch","IN3R"},
- {"Right Input Mixer","IN4R Switch","IN4R"},
- {"Right Input Mixer","IN2L Switch","IN2L"},
+ /* Right Positive PGA Input */
+ {"Right Input Mixer", "IN1R Switch", "IN1R"},
+ {"Right Input Mixer", "IN2R Switch", "IN2R"},
+ {"Right Input Mixer", "IN3R Switch", "IN3R"},
+ {"Right Input Mixer", "IN4R Switch", "IN4R"},
+ {"Right Input Mixer", "IN2L Switch", "IN2L"},
/* Right Negative PGA Input */
- {"Right Input Mixer","IN1L Switch","IN1L"},
- {"Right Input Mixer","IN3L Switch","IN3L"},
- {"Right Input Mixer","IN4L Switch","IN4L"},
- {"Right Input Mixer","CM1R Switch","CM1R"},
- {"Right Input Mixer","CM2R Switch","CM2R"},
+ {"Right Input Mixer", "IN1L Switch", "IN1L"},
+ {"Right Input Mixer", "IN3L Switch", "IN3L"},
+ {"Right Input Mixer", "IN4L Switch", "IN4L"},
+ {"Right Input Mixer", "CM1R Switch", "CM1R"},
+ {"Right Input Mixer", "CM2R Switch", "CM2R"},
+
{"CM1L", NULL, "CM"},
{"CM2L", NULL, "CM"},
{"CM1R", NULL, "CM"},
{"CM2R", NULL, "CM"},
- {"Left MicPGA",NULL,"Left Input Mixer"},
- {"Right MicPGA",NULL,"Right Input Mixer"},
+ {"Left MicPGA", NULL, "Left Input Mixer"},
+ {"Right MicPGA", NULL, "Right Input Mixer"},
- {"Left ADC", NULL, "Left MicPGA"},
- {"Right ADC", NULL, "Right MicPGA"},
+ {"Left ADC Route", "Analog", "Left MicPGA"},
+ {"Left ADC Route", "Digital", "Left DMIC"},
-/* ASI Output Routing */
+ {"Right ADC Route", "Analog", "Right MicPGA"},
+ {"Right ADC Route", "Digital", "Right DMIC"},
+
+ {"Left ADC", NULL, "Left ADC Route"},
+ {"Right ADC", NULL, "Right ADC Route"},
+
+ /* ASI Output Routing */
{"ADC MiniDSP OUT1", NULL, "Left ADC"},
{"ADC MiniDSP OUT1", NULL, "Right ADC"},
{"ADC MiniDSP OUT2", NULL, "Left ADC"},
@@ -3435,459 +1502,673 @@ static const struct snd_soc_dapm_route aic3262_dapm_routes[] ={
{"ADC MiniDSP OUT3", NULL, "Left ADC"},
{"ADC MiniDSP OUT3", NULL, "Right ADC"},
- {"ASI1OUT Route", "ASI1 Out","ADC MiniDSP OUT1"},// Port 1
- {"ASI1OUT Route", "ASI1In Bypass","ASI1IN Port"},
- {"ASI1OUT Route", "ASI2In Bypass","ASI2IN Port"},
- {"ASI1OUT Route", "ASI3In Bypass","ASI3IN Port"},
-
- {"ASI2OUT Route", "ASI1 Out","ADC MiniDSP OUT1"},// Port 1
- {"ASI2OUT Route", "ASI1In Bypass","ASI1IN Port"},
- {"ASI2OUT Route", "ASI2In Bypass","ASI2IN Port"},
- {"ASI2OUT Route", "ASI3In Bypass","ASI3IN Port"},
- {"ASI2OUT Route", "ASI2 Out","ADC MiniDSP OUT2"},// Port 2
-
- {"ASI3OUT Route", "ASI1 Out","ADC MiniDSP OUT1"},// Port 1
- {"ASI3OUT Route", "ASI1In Bypass","ASI1IN Port"},
- {"ASI3OUT Route", "ASI2In Bypass","ASI2IN Port"},
- {"ASI3OUT Route", "ASI3In Bypass","ASI3IN Port"},
- {"ASI3OUT Route", "ASI3 Out","ADC MiniDSP OUT3"},// Port 3
-
- {"ASI1OUT",NULL,"ASI1OUT Route"},
- {"ASI2OUT",NULL,"ASI2OUT Route"},
- {"ASI3OUT",NULL,"ASI3OUT Route"},
-
+ {"ASI1OUT Route", "ADC MiniDSP Out1", "ADC MiniDSP OUT1"},
+ {"ASI1OUT Route", "ASI1In Bypass", "ASI1IN Port"},
+ {"ASI1OUT Route", "ASI2In Bypass", "ASI2IN Port"},
+ {"ASI1OUT Route", "ASI3In Bypass", "ASI3IN Port"},
+
+ {"ASI2OUT Route", "ADC MiniDSP Out1", "ADC MiniDSP OUT1"},
+ {"ASI2OUT Route", "ASI1In Bypass", "ASI1IN Port"},
+ {"ASI2OUT Route", "ASI2In Bypass", "ASI2IN Port"},
+ {"ASI2OUT Route", "ASI3In Bypass", "ASI3IN Port"},
+ {"ASI2OUT Route", "ADC MiniDSP Out2", "ADC MiniDSP OUT2"},
+
+ {"ASI3OUT Route", "ADC MiniDSP Out1", "ADC MiniDSP OUT1"},
+ {"ASI3OUT Route", "ASI1In Bypass", "ASI1IN Port"},
+ {"ASI3OUT Route", "ASI2In Bypass", "ASI2IN Port"},
+ {"ASI3OUT Route", "ASI3In Bypass", "ASI3IN Port"},
+ {"ASI3OUT Route", "ADC MiniDSP Out3", "ADC MiniDSP OUT3"},
+
+ {"ASI1OUT", NULL, "ASI1OUT Route"},
+ {"ASI2OUT", NULL, "ASI2OUT Route"},
+ {"ASI3OUT", NULL, "ASI3OUT Route"},
+
+ {"DOUT1 Route", "ASI1 Out", "ASI1OUT"},
+ {"DOUT1 Route", "DIN1 Bypass", "DIN1"},
+ {"DOUT1 Route", "DIN2 Bypass", "DIN2"},
+ {"DOUT1 Route", "DIN3 Bypass", "DIN3"},
+
+ {"DOUT2 Route", "ASI2 Out", "ASI2OUT"},
+ {"DOUT2 Route", "DIN1 Bypass", "DIN1"},
+ {"DOUT2 Route", "DIN2 Bypass", "DIN2"},
+ {"DOUT2 Route", "DIN3 Bypass", "DIN3"},
+
+ {"DOUT3 Route", "ASI3 Out", "ASI3OUT"},
+ {"DOUT3 Route", "DIN1 Bypass", "DIN1"},
+ {"DOUT3 Route", "DIN2 Bypass", "DIN2"},
+ {"DOUT3 Route", "DIN3 Bypass", "DIN3"},
+
+ {"DOUT1", NULL, "DOUT1 Route"},
+ {"DOUT2", NULL, "DOUT2 Route"},
+ {"DOUT3", NULL, "DOUT3 Route"},
};
+#define AIC3262_DAPM_ROUTE_NUM (ARRAY_SIZE(aic3262_dapm_routes)/ \
+ sizeof(struct snd_soc_dapm_route))
+/* aic3262_firmware_load: This function is called by the
+ * request_firmware_nowait function as soon
+ * as the firmware has been loaded from the file.
+ * The firmware structure contains the data and$
+ * the size of the firmware loaded.
+ * @fw: pointer to firmware file to be dowloaded
+ * @context: pointer variable to codec
+ *
+ * Returns 0 for success.
+ */
+void aic3262_firmware_load(const struct firmware *fw, void *context)
+{
+ struct snd_soc_codec *codec = context;
+ struct aic3262_priv *private_ds = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
-#define AIC3262_DAPM_ROUTE_NUM (sizeof(aic3262_dapm_routes)/sizeof(struct snd_soc_dapm_route))
+ aic3xxx_cfw_lock(private_ds->cfw_p, 1);
+ if (private_ds->cur_fw != NULL)
+ release_firmware(private_ds->cur_fw);
+ private_ds->cur_fw = NULL;
+
+ if (fw != NULL) {
+ dev_dbg(codec->dev, "Firmware binary load\n");
+ private_ds->cur_fw = (void *)fw;
+ ret = aic3xxx_cfw_reload(private_ds->cfw_p,
+ (void *)fw->data, fw->size);
+ if (ret < 0) { /* reload failed */
+ dev_err(codec->dev, "Firmware binary load failed\n");
+ release_firmware(private_ds->cur_fw);
+ private_ds->cur_fw = NULL;
+ fw = NULL;
+ } else
+ private_ds->isdefault_fw = 0;
+ }
+
+ if (fw == NULL) {
+ /* either request_firmware or reload failed */
+ dev_dbg(codec->dev, "Default firmware load\n");
+ ret = aic3xxx_cfw_reload(private_ds->cfw_p, default_firmware,
+ sizeof(default_firmware));
+ if (ret < 0)
+ dev_err(codec->dev, "Default firmware load failed\n");
+ else
+ private_ds->isdefault_fw = 1;
+ }
+ aic3xxx_cfw_lock(private_ds->cfw_p, 0);
+ if (ret >= 0) {
+ /* init function for transition */
+ aic3xxx_cfw_transition(private_ds->cfw_p, "INIT");
+ if (!private_ds->isdefault_fw) {
+ aic3xxx_cfw_add_modes(codec, private_ds->cfw_p);
+ aic3xxx_cfw_add_controls(codec, private_ds->cfw_p);
+ }
+ aic3xxx_cfw_setmode_cfg(private_ds->cfw_p, 0, 0);
+ }
+}
-/*
- *****************************************************************************
- * Function Definitions
- *****************************************************************************
- */
+/*=========================================================
+ headset work and headphone/headset jack interrupt handlers
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_change_page
- * Purpose : This function is to switch between page 0 and page 1.
+ ========================================================*/
+
+/**
+ * aic3262_hs_jack_report: Report jack notication to upper layor
+ * @codec: pointer variable to codec having information related to codec
+ * @jack: Pointer variable to snd_soc_jack having information of codec
+ * and pin number$
+ * @report: Provides informaton of whether it is headphone or microphone
*
- *----------------------------------------------------------------------------
- */
-int aic3262_change_page(struct snd_soc_codec *codec, u8 new_page)
+*/
+static void aic3262_hs_jack_report(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, int report)
{
struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 data[2];
- int ret = 0;
+ int status, state = 0;
- data[0] = 0;
- data[1] = new_page;
- aic3262->page_no = new_page;
+ mutex_lock(&aic3262->mutex);
-#if defined(LOCAL_REG_ACCESS)
- if (codec->hw_write(codec->control_data, data, 2) != 2)
- ret = -EIO;
-#else
- ret = snd_soc_write(codec, data[0], data[1]);
-#endif
- if (ret)
- printk(KERN_ERR "Error in changing page to %d\n", new_page);
+ /* Sync status */
+ status = snd_soc_read(codec, AIC3262_DAC_FLAG);
+ /* We will check only stereo MIC and headphone */
+ if (status & AIC3262_JACK_WITH_STEREO_HS)
+ state |= SND_JACK_HEADPHONE;
+ if (status & AIC3262_JACK_WITH_MIC)
+ state |= SND_JACK_MICROPHONE;
- /*DBG("# Changing page to %d\r\n", new_page);*/
+ mutex_unlock(&aic3262->mutex);
+
+ snd_soc_jack_report(jack, state, report);
- return ret;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_change_book
- * Purpose : This function is to switch between books
+
+/**
+ * aic3262_hs_jack_detect: Detect headphone jack during boot time
+ * @codec: pointer variable to codec having information related to codec
+ * @jack: Pointer variable to snd_soc_jack having information of codec
+ * and pin number$
+ * @report: Provides informaton of whether it is headphone or microphone
*
- *----------------------------------------------------------------------------
- */
-int aic3262_change_book(struct snd_soc_codec *codec, u8 new_book)
+*/
+void aic3262_hs_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, int report)
{
struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 data[2];
- int ret = 0;
+ struct aic3262_jack_data *hs_jack = &aic3262->hs_jack;
- data[0] = 0x7F;
- data[1] = new_book;
- aic3262->book_no = new_book;
+ hs_jack->jack = jack;
+ hs_jack->report = report;
+ aic3262_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
+EXPORT_SYMBOL_GPL(aic3262_hs_jack_detect);
+/**
+ * aic3262_accessory_work: Finished bottom half work from headphone jack
+ * insertion interupt
+ * @work: pionter variable to work_struct which is maintaining work queqe
+ *
+*/
+static void aic3262_accessory_work(struct work_struct *work)
+{
+ struct aic3262_priv *aic3262 = container_of(work,
+ struct aic3262_priv,
+ delayed_work.work);
+ struct snd_soc_codec *codec = aic3262->codec;
+ struct aic3262_jack_data *hs_jack = &aic3262->hs_jack;
+ aic3262_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
+}
- ret = aic3262_change_page(codec, 0);
- if (ret)
- return ret;
+/**
+ * aic3262_audio_handler: audio interrupt handler called
+ * when interupt is generated
+ * @irq: provides interupt number which is assigned by aic3262_request_irq,
+ * @data having information of data passed by aic3262_request_irq last arg,
+ *
+ * Return IRQ_HANDLED(means interupt handeled successfully)
+*/
+static irqreturn_t aic3262_audio_handler(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-#if defined(LOCAL_REG_ACCESS)
- if (codec->hw_write(codec->control_data, data, 2) != 2)
- ret = -EIO;
-#else
- ret = snd_soc_write(codec, data[0], data[1]);
-#endif
- if (ret)
- printk(KERN_ERR "Error in changing Book\n");
+ queue_delayed_work(aic3262->workqueue, &aic3262->delayed_work,
+ msecs_to_jiffies(200));
+ return IRQ_HANDLED;
+}
- /*DBG("# Changing book to %d\r\n", new_book);*/
+static irqreturn_t aic3262_button_handler(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+ input_report_key(aic3262->idev, KEY_MEDIA, 1);
+ mdelay(50);
+ input_report_key(aic3262->idev, KEY_MEDIA, 0);
+ input_sync(aic3262->idev);
- return ret;
+ return IRQ_HANDLED;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_write_reg_cache
- * Purpose : This function is to write aic3262 register cache
+
+/**
+ * aic3262_codec_read: provide read api to read aic3262 registe space
+ * @codec: pointer variable to codec having codec information,
+ * @reg: register address,
*
- *----------------------------------------------------------------------------
+ * Return: Return value will be value read.
*/
-void aic3262_write_reg_cache(struct snd_soc_codec *codec,
- u16 reg, u8 value)
+unsigned int aic3262_codec_read(struct snd_soc_codec *codec, unsigned int reg)
{
-#if defined(EN_REG_CACHE)
- u8 *cache = codec->reg_cache;
- if (reg >= AIC3262_CACHEREGNUM)
- return;
+ u8 value;
- if (cache)
- cache[reg] = value;
-#endif
+ union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+ value = aic3262_reg_read(codec->control_data, reg);
+ dev_dbg(codec->dev, "p %d , r 30 %x %x\n",
+ aic_reg->aic326x_register.page,
+ aic_reg->aic326x_register.offset, value);
+ return value;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_read
- * Purpose : This function is to read the aic3262 register space.
+/**
+ * aic3262_codec_write: provide write api to write at aic3262 registe space
+ * @codec: Pointer variable to codec having codec information,
+ * @reg: Register address,
+ * @value: Value to be written to address space
*
- *----------------------------------------------------------------------------
+ * Return: Total no of byte written to address space.
*/
+int aic3262_codec_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ union aic326x_reg_union *aic_reg = (union aic326x_reg_union *) &reg;
+ dev_dbg(codec->dev, "p %d, w 30 %x %x\n",
+ aic_reg->aic326x_register.page,
+ aic_reg->aic326x_register.offset, value);
+ return aic3262_reg_write(codec->control_data, reg, value);
+}
-unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg)
+/**
+ * aic3262_add_widget: This function is to add the dapm widgets
+ * The following are the main widgets supported
+ * # Left DAC to Left Outputs
+ * # Right DAC to Right Outputs
+ * # Left Inputs to Left ADC
+ * # Right Inputs to Right ADC
+ * @codec: pointer variable to codec having informaton related to codec,
+ *
+ * Return: return 0 on success.
+ */
+static int aic3262_add_widgets(struct snd_soc_codec *codec)
{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 value;
- u8 page = reg / 128;
- u16 *cache = codec->reg_cache;
- u16 cmd;
- u8 buffer[2];
- int rc = 0;
- reg = reg % 128;
-
- if (reg >= AIC3262_CACHEREGNUM) {
- return 0;
- }
- if (aic3262->control_type == SND_SOC_I2C) {
- if (aic3262->page_no != page) {
- aic3262_change_page(codec, page);
- }
- i2c_master_send(codec->control_data, (char *)&reg, 1);
- i2c_master_recv(codec->control_data, &value, 1);
- /*DBG("r %2x %02x\r\n", reg, value); */
- } else if (aic3262->control_type == SND_SOC_SPI) {
- u16 value;
-
- /* Do SPI transfer; first 16bits are command; remaining is
- * register contents */
- cmd = AIC3262_READ_COMMAND_WORD(reg);
- buffer[0] = (cmd >> 8) & 0xff;
- buffer[1] = cmd & 0xff;
- //rc = spi_write_then_read(aic3262->spi, buffer, 2, buffer, 2);
-
- if (rc) {
- dev_err(&aic3262->spi->dev, "AIC26 reg read error\n");
- return -EIO;
- }
- value = (buffer[0] << 8) | buffer[1];
- } else {
- printk(KERN_ERR "Unknown Interface Type in aic3262_read\n");
- }
+ snd_soc_dapm_new_controls(&codec->dapm, aic3262_dapm_widgets,
+ ARRAY_SIZE(aic3262_dapm_widgets));
+ /* set up audio path interconnects */
+ dev_dbg(codec->dev, "#Completed adding new dapm widget"
+ " controls size=%d\n", ARRAY_SIZE(aic3262_dapm_widgets));
- /* Update the cache before returning with the value */
- cache[reg] = value;
- return value;
+ snd_soc_dapm_add_routes(&codec->dapm, aic3262_dapm_routes,
+ ARRAY_SIZE(aic3262_dapm_routes));
+ dev_dbg(codec->dev, "#Completed adding DAPM routes\n");
+ snd_soc_dapm_new_widgets(&codec->dapm);
+ dev_dbg(codec->dev, "#Completed updating dapm\n");
+ return 0;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_write
- * Purpose : This function is to write to the aic3262 register space.
+/**
+ * aic3262_set_interface_fmt: Setting interface ASI1/2/3 data format
+ * @dai: ponter to dai Holds runtime data for a DAI,
+ * @fmt: asi format info,
+ * @channel: number of channel,
*
- *----------------------------------------------------------------------------
- */
-int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
+ * Return: On success return 0.
+*/
+static int aic3262_set_interface_fmt(struct snd_soc_dai *dai, unsigned int fmt,
+ unsigned int channel)
{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 data[2];
- u8 page;
- int ret = 0;
-
- page = reg / 128;
- data[AIC3262_REG_OFFSET_INDEX] = reg % 128;
- if (aic3262->page_no != page)
- aic3262_change_page(codec, page);
+ int aif_interface_reg;
+ int aif_bclk_offset_reg;
+ struct snd_soc_codec *codec = dai->codec;
+ u8 iface_val = 0;
+ u8 dsp_a_val = 0;
- /* data is
- * D15..D8 aic3262 register offset
- * D7...D0 register data
- */
- data[AIC3262_REG_DATA_INDEX] = value & AIC3262_8BITS_MASK;
-#if defined(EN_REG_CACHE)
- if ((page >= 0) & (page <= 4))
- aic3262_write_reg_cache(codec, reg, value);
+ switch (dai->id) {
+ case 0:
+ aif_interface_reg = AIC3262_ASI1_BUS_FMT;
+ aif_bclk_offset_reg = AIC3262_ASI1_LCH_OFFSET;
+ break;
+ case 1:
+ aif_interface_reg = AIC3262_ASI2_BUS_FMT;
+ aif_bclk_offset_reg = AIC3262_ASI2_LCH_OFFSET;
+ break;
+ case 2:
+ aif_interface_reg = AIC3262_ASI3_BUS_FMT;
+ aif_bclk_offset_reg = AIC3262_ASI3_LCH_OFFSET;
+ break;
+ default:
+ return -EINVAL;
-#endif
- if (!data[AIC3262_REG_OFFSET_INDEX]) {
- /* if the write is to reg0 update aic3262->page_no */
- aic3262->page_no = value;
}
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface_val = 0;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ dsp_a_val = 0x1; /* Intentionally falling back
+ to following case */
+ case SND_SOC_DAIFMT_DSP_B:
+ switch (channel) {
+ case 1:
+ iface_val = 0x80; /* Choose mono PCM */
+ break;
+ case 2:
+ iface_val = 0x20;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iface_val = 0x40;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface_val = 0x60;
+ break;
+ default:
+ dev_err(codec->dev, "Invalid DAI interface format\n");
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, aif_interface_reg,
+ AIC3262_ASI_INTERFACE_MASK, iface_val);
+ snd_soc_update_bits(codec, aif_bclk_offset_reg,
+ AIC3262_BCLK_OFFSET_MASK, dsp_a_val);
+ return 0;
- /*DBG("w %2x %02x\r\n",
- data[AIC3262_REG_OFFSET_INDEX], data[AIC3262_REG_DATA_INDEX]);*/
-
-#if defined(LOCAL_REG_ACCESS)
- if (codec->hw_write(codec->control_data, data, 2) != 2)
- ret = -EIO;
-#else
- ret = snd_soc_write(codec, data[AIC3262_REG_OFFSET_INDEX],
- data[AIC3262_REG_DATA_INDEX]);
-#endif
- if (ret)
- printk(KERN_ERR "Error in i2c write\n");
-
- return ret;
}
-/*
- *------------------------------------------------------------------------------
- * Function : aic3262_write__
- * Purpose : This function is to write to the aic3262 register space.
- * (low level).
- *------------------------------------------------------------------------------
+/**
+ * aic3262_hw_params: This function is to set the hardware parameters
+ * for AIC3262.
+ * The functions set the sample rate and audio serial data word
+ * length.
+ * @substream: pointer variable to sn_pcm_substream,
+ * @params: pointer to snd_pcm_hw_params structure,
+ * @dai: ponter to dai Holds runtime data for a DAI,
+ *
+ * Return: Return 0 on success.
*/
-
-int aic3262_write__(struct i2c_client *client, const char *buf, int count)
+int aic3262_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- u8 data[3];
- int ret;
- data[0] = *buf;
- data[1] = *(buf+1);
- data[2] = *(buf+2);
- /*DBG("w %2x %02x\r\n",
- data[AIC3262_REG_OFFSET_INDEX], data[AIC3262_REG_DATA_INDEX]);*/
- ret = i2c_master_send(client, data, 2);
- if (ret < 2) {
- printk(
- KERN_ERR "I2C write Error : bytes written = %d\n\n", ret);
- return -EIO;
- }
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+ int asi_reg;
+ u8 data = 0;
- return ret;
-}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_reset_cache
- * Purpose : This function is to reset the cache.
- *----------------------------------------------------------------------------
- */
-int aic3262_reset_cache(struct snd_soc_codec *codec)
-{
-#if defined(EN_REG_CACHE)
- if (codec->reg_cache) {
- memcpy(codec->reg_cache, aic3262_reg, sizeof(aic3262_reg));
- return 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ aic3262->stream_status = 1;
+ else
+ aic3262->stream_status = 0;
+
+ switch (dai->id) {
+ case 0:
+ asi_reg = AIC3262_ASI1_BUS_FMT;
+ break;
+ case 1:
+ asi_reg = AIC3262_ASI2_BUS_FMT;
+ break;
+ case 2:
+ asi_reg = AIC3262_ASI3_BUS_FMT;
+ break;
+ default:
+ return -EINVAL;
}
- codec->reg_cache = kmemdup(aic3262_reg,
- sizeof(aic3262_reg), GFP_KERNEL);
- if (!codec->reg_cache) {
- printk(KERN_ERR "aic32x4: kmemdup failed\n");
- return -ENOMEM;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ data = data | 0x00;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ data |= (0x08);
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ data |= (0x10);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ data |= (0x18);
+ break;
}
-#endif
- return 0;
+
+ /* configure the respective Registers for the above configuration */
+ snd_soc_update_bits(codec, asi_reg,
+ AIC3262_ASI_DATA_WORD_LENGTH_MASK, data);
+ return aic3262_set_interface_fmt(dai, aic3262->asi_fmt[dai->id],
+ params_channels(params));
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_get_divs
- * Purpose : This function is to get required divisor from the "aic3262_divs"
- * table.
+/**
+ * aic3262_mute: This function is to mute or unmute the left and right DAC
+ * @dai: ponter to dai Holds runtime data for a DAI,
+ * @mute: integer value one if we using mute else unmute,
*
- *----------------------------------------------------------------------------
+ * Return: return 0 on success.
*/
-static inline int aic3262_get_divs(int mclk, int rate)
+static int aic3262_mute(struct snd_soc_dai *dai, int mute)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(aic3262_divs); i++) {
- if ((aic3262_divs[i].rate == rate)
- && (aic3262_divs[i].mclk == mclk)) {
- DBG(KERN_INFO "#%s: Found Entry %d in Clock_Array\n",
- __func__, i);
- return i;
- }
- }
- printk(KERN_ERR "Master clock and sample rate is not supported\n");
- return -EINVAL;
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "codec : %s : started\n", __func__);
+ if (dai->id > 2)
+ return -EINVAL;
+ if (mute) {
+ aic3262->mute_asi &= ~((0x1) << dai->id);
+ if (aic3262->mute_asi == 0)
+ /* Mute only when all asi's are muted */
+ snd_soc_update_bits_locked(codec,
+ AIC3262_DAC_MVOL_CONF,
+ AIC3262_DAC_LR_MUTE_MASK,
+ AIC3262_DAC_LR_MUTE);
+
+ } else { /* Unmute */
+ if (aic3262->mute_asi == 0)
+ /* Unmute for the first asi that need to unmute.
+ rest unmute will pass */
+ snd_soc_update_bits_locked(codec,
+ AIC3262_DAC_MVOL_CONF,
+ AIC3262_DAC_LR_MUTE_MASK,
+ 0x0);
+ aic3262->mute_asi |= ((0x1) << dai->id);
+ }
+ dev_dbg(codec->dev, "codec : %s : ended\n", __func__);
+ return 0;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_add_widgets
- * Purpose : This function is to add the dapm widgets
- * The following are the main widgets supported
- * # Left DAC to Left Outputs
- * # Right DAC to Right Outputs
- * # Left Inputs to Left ADC
- * # Right Inputs to Right ADC
+/**
+ * aic3262_set_dai_sysclk: This function is to set the DAI system clock
+ * @codec_dai: ponter to dai Holds runtime data for a DAI,
+ * @freq: system clock to be set,
+ * @dir: integer dir,
*
- *----------------------------------------------------------------------------
+ * Return: return 0 on success.
*/
-static int aic3262_add_widgets(struct snd_soc_codec *codec)
+static int aic3262_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
{
- int ret;
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-#ifndef AIC3262_MULTI_I2S
- int i;
- for (i = 0; i < ARRAY_SIZE(aic3262_dapm_widgets); i++)
- ret = snd_soc_dapm_new_control(dapm, &aic3262_dapm_widgets[i]);
-#else
- ret = snd_soc_dapm_new_controls(dapm, aic3262_dapm_widgets,
- ARRAY_SIZE(aic3262_dapm_widgets));
- if (ret != 0) {
- printk(KERN_ERR "#%s: Unable to add DAPM Controls. Err %d\n",
- __func__, ret);
+ struct aic3262_priv *aic3262;
+ struct snd_soc_codec *codec;
+
+ codec = codec_dai->codec;
+ aic3262 = snd_soc_codec_get_drvdata(codec);
+ switch (freq) {
+ case AIC3262_FREQ_12000000:
+ aic3262->sysclk = freq;
+ return 0;
+ case AIC3262_FREQ_24000000:
+ aic3262->sysclk = freq;
+ return 0;
+ break;
+ case AIC3262_FREQ_19200000:
+ aic3262->sysclk = freq;
+ return 0;
+ break;
+ case AIC3262_FREQ_38400000:
+ aic3262->sysclk = freq;
+ dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk);
+ return 0;
+ break;
+ case AIC3262_FREQ_12288000:
+ aic3262->sysclk = freq;
+ dev_dbg(codec->dev, "codec: sysclk = %d\n", aic3262->sysclk);
+ return 0;
+ break;
+
}
-#endif
- /* set up audio path interconnects */
- DBG("#Completed adding new dapm widget controls size=%d\n",
- ARRAY_SIZE(aic3262_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, aic3262_dapm_routes,
- ARRAY_SIZE(aic3262_dapm_routes));
- DBG("#Completed adding DAPM routes\n");
- snd_soc_dapm_new_widgets(dapm);
- DBG("#Completed updating dapm\n");
- return 0;
+ dev_err(codec->dev, "Invalid frequency to set DAI system clock\n");
+
+ return -EINVAL;
}
-/*
- *----------------------------------------------------------------------------
- * Function : reg_def_conf
- * Purpose : This function is to reset the codec book 0 registers
+
+/**
+ * aic3262_set_dai_fmt: This function is to set the DAI format
+ * @codec_dai: ponter to dai Holds runtime data for a DAI,
+ * @fmt: asi format info,
*
- *----------------------------------------------------------------------------
+ * return: return 0 on success.
*/
-int reg_def_conf(struct snd_soc_codec *codec)
+static int aic3262_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
- int i = 0, ret;
- DBG(KERN_INFO "#%s: Invoked..\n", __func__);
+ struct aic3262_priv *aic3262;
+ struct snd_soc_codec *codec;
+ u8 iface_val, master;
+ int aif_bclk_wclk_reg;
- ret = aic3262_change_page(codec, 0);
- if (ret != 0)
- return ret;
+ codec = codec_dai->codec;
+ aic3262 = snd_soc_codec_get_drvdata(codec);
+ iface_val = 0x00;
+ master = 0x0;
- ret = aic3262_change_book(codec, 0);
- if (ret != 0)
- return ret;
+ switch (codec_dai->id) {
+ case 0:
+ aif_bclk_wclk_reg = AIC3262_ASI1_BWCLK_CNTL_REG;
+ break;
+ case 1:
+ aif_bclk_wclk_reg = AIC3262_ASI2_BWCLK_CNTL_REG;
+ break;
+ case 2:
+ aif_bclk_wclk_reg = AIC3262_ASI3_BWCLK_CNTL_REG;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ aic3262->asi_fmt[codec_dai->id] = fmt;
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aic3262->master = 1;
+ master |= (AIC3262_WCLK_OUT_MASK | AIC3262_BCLK_OUT_MASK);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ aic3262->master = 0;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM: /* new case..just for debugging */
+ master |= (AIC3262_WCLK_OUT_MASK);
+ aic3262->master = 0;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ master |= (AIC3262_BCLK_OUT_MASK);
+ aic3262->master = 0;
+ break;
- /* Configure the Codec with the default Initialization Values */
- for (i = 0; i < reg_init_size; i++) {
- ret = snd_soc_write(codec, aic3262_reg_init[i].reg_offset,
- aic3262_reg_init[i].reg_val);
- if (ret)
+ default:
+ dev_err(codec->dev, "Invalid DAI master/slave" " interface\n");
+
+ return -EINVAL;
+ }
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ master |= AIC3262_BCLK_INV_MASK;
break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ case SND_SOC_DAIFMT_LEFT_J:
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ master |= AIC3262_BCLK_INV_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
}
- DBG(KERN_INFO "#%s: Done..\n", __func__);
- return ret;
+ snd_soc_update_bits(codec, aif_bclk_wclk_reg,
+ AIC3262_WCLK_BCLK_MASTER_MASK, master);
+ return 0;
}
-/*
- * i2c_verify_book0
+/**
+ * aic3262_dai_set_pll: This function is to Set pll for aic3262 codec dai
+ * @dai: ponter to dai Holds runtime data for a DAI,$
+ * @pll_id: integer pll_id
+ * @fin: frequency in,
+ * @fout: Frequency out,
*
- * This function is used to dump the values of the Book 0 Pages.
- */
-int i2c_verify_book0(struct snd_soc_codec *codec)
+ * Return: return 0 on success
+*/
+static int aic3262_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
+ unsigned int Fin, unsigned int Fout)
{
- int i, j, k = 0;
- u8 val1;
-
- DBG("starting i2c_verify\n");
- DBG("Resetting page to 0\n");
- aic3262_change_book(codec, 0);
- for (j = 0; j < 3; j++) {
- if (j == 0) {
- aic3262_change_page(codec, 0);
- k = 0;
- }
- if (j == 1) {
- aic3262_change_page(codec, 1);
- k = 1;
- }
- /*
- if (j == 2) {
- aic3262_change_page(codec, 4);
- k = 4;
- }*/
- for (i = 0; i <= 127; i++) {
-#if defined(LOCAL_REG_ACCESS)
- val1 = i2c_smbus_read_byte_data(codec->control_data, i);
-#else
- val1 = snd_soc_read(codec, i);
-#endif
- /* printk("[%d][%d]=[0x%2x]\n",k,i,val1); */
- }
- }
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "In aic3262: dai_set_pll\n");
+ dev_dbg(codec->dev, "%d, %s, dai->id = %d\n", __LINE__,
+ __func__, dai->id);
+ /* select the PLL_CLKIN */
+ snd_soc_update_bits(codec, AIC3262_PLL_CLKIN_REG,
+ AIC3262_PLL_CLKIN_MASK, source <<
+ AIC3262_PLL_CLKIN_SHIFT);
+ /* TODO: How to select low/high clock range? */
+
+ aic3xxx_cfw_set_pll(aic3262->cfw_p, dai->id);
return 0;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_set_bias_level
- * Purpose : This function is to get triggered when dapm events occurs.
+/**
*
- *----------------------------------------------------------------------------
+ * aic3262_set_bias_level: This function is to get triggered
+ * when dapm events occurs.
+ * @codec: pointer variable to codec having informaton related to codec,
+ * @level: Bias level-> ON, PREPARE, STANDBY, OFF.
+ *
+ * Return: Return 0 on success.
*/
-
static int aic3262_set_bias_level(struct snd_soc_codec *codec,
- enum snd_soc_bias_level level)
+ enum snd_soc_bias_level level)
{
+
switch (level) {
/* full On */
case SND_SOC_BIAS_ON:
- /* all power is driven by DAPM system */
dev_dbg(codec->dev, "set_bias_on\n");
break;
/* partial On */
case SND_SOC_BIAS_PREPARE:
-
dev_dbg(codec->dev, "set_bias_prepare\n");
-
break;
- /* Off, with power */
+ /* Off, with power */
case SND_SOC_BIAS_STANDBY:
/*
* all power is driven by DAPM system,
* so output power is safe if bypass was set
*/
- dev_dbg(codec->dev, "set_bias_stby\n");
+ dev_dbg(codec->dev, "set_bias_stby\n");
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_update_bits(codec, AIC3262_POWER_CONF,
+ (AIC3262_AVDD_TO_DVDD_MASK |
+ AIC3262_EXT_ANALOG_SUPPLY_MASK),
+ 0x0);
+ snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY,
+ AIC3262_CHIP_REF_PWR_ON_MASK,
+ AIC3262_CHIP_REF_PWR_ON);
+ mdelay(40);
+ }
break;
- /* Off, without power */
- case SND_SOC_BIAS_OFF:
- dev_dbg(codec->dev, "set_bias_off\n");
+ /* Off, without power */
+ case SND_SOC_BIAS_OFF:
+ dev_dbg(codec->dev, "set_bias_off\n");
+ if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+ snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY,
+ AIC3262_CHIP_REF_PWR_ON_MASK, 0x0);
+ snd_soc_update_bits(codec, AIC3262_POWER_CONF,
+ (AIC3262_AVDD_TO_DVDD_MASK |
+ AIC3262_EXT_ANALOG_SUPPLY_MASK),
+ (AIC3262_AVDD_TO_DVDD |
+ AIC3262_EXT_ANALOG_SUPPLY_OFF));
+ }
break;
}
- codec->dapm.bias_level=level;
+ codec->dapm.bias_level = level;
return 0;
}
-
/*
*----------------------------------------------------------------------------
* Function : aic3262_suspend
@@ -3897,13 +2178,7 @@ static int aic3262_set_bias_level(struct snd_soc_codec *codec,
*/
static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- DBG(KERN_INFO "#%s: Invoked..\n", __func__);
- if (aic3262)
- disable_irq(aic3262->irq);
-
- aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
+ aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -3916,207 +2191,10 @@ static int aic3262_suspend(struct snd_soc_codec *codec, pm_message_t state)
*/
static int aic3262_resume(struct snd_soc_codec *codec)
{
- int i;
- u8 data[2];
- int ret = 0;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u8 *cache = codec->reg_cache;
- DBG(KERN_INFO "#%s: Invoked..\n", __func__);
-
- ret = aic3262_change_page(codec, 0);
- if (ret)
- return ret;
-#if defined(EN_REG_CACHE)
- /* Sync reg_cache with the hardware */
- for (i = 0; i < ARRAY_SIZE(aic3262_reg); i++) {
- data[0] = i % 128;
- data[1] = cache[i];
-#if defined(LOCAL_REG_ACCESS)
- codec->hw_write(codec->control_data, data, 2);
-#else
- ret = snd_soc_write(codec, data[0], data[1]);
- if (ret)
- break;
-#endif
- }
-#endif
- if (!ret) {
- aic3262_change_page(codec, 0);
- aic3262_set_bias_level(codec, SND_SOC_BIAS_ON);
-
- if (aic3262)
- enable_irq(aic3262->irq);
- }
- return ret;
-}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_hw_read
- * Purpose : This is a low level harware read function.
- *
- *----------------------------------------------------------------------------
- */
-unsigned int aic3262_hw_read(struct snd_soc_codec *codec, unsigned int count)
-{
- struct i2c_client *client = codec->control_data;
- unsigned int buf;
-
- if (count > (sizeof(unsigned int)))
- return 0;
-
- i2c_master_recv(client, (char *)&buf, count);
- return buf;
-}
-
-/*
-* aic3262_jack_handler
-*
-* This function is called from the Interrupt Handler
-* to check the status of the AIC3262 Registers related to Headset Detection
-*/
-static irqreturn_t aic3262_jack_handler(int irq, void *data)
-{
- struct snd_soc_codec *codec = data;
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- unsigned int value;
- unsigned int micbits, hsbits = 0;
- DBG(KERN_INFO "%s++\n", __func__);
-
- aic3262_change_page(codec, 0);
-
- /* Read the Jack Status Register*/
- value = snd_soc_read(codec, STICKY_FLAG2);
- DBG(KERN_INFO "reg44 0x%x\n", value);
-
-
- value = snd_soc_read(codec, INT_FLAG2);
- DBG(KERN_INFO "reg46 0x%x\n", value);
-
- value = snd_soc_read(codec, DAC_FLAG_R1);
- DBG(KERN_INFO "reg37 0x%x\n", value);
-
- micbits = value & DAC_FLAG_MIC_MASKBITS;
- DBG(KERN_INFO "micbits 0x%x\n", micbits);
-
- hsbits = value & DAC_FLAG_HS_MASKBITS;
- DBG(KERN_INFO "hsbits 0x%x\n", hsbits);
-
-
- /* No Headphone or Headset*/
- if (!micbits && !hsbits) {
- DBG(KERN_INFO "no headset/headphone\n");
- snd_soc_jack_report(aic3262->headset_jack,
- 0, SND_JACK_HEADSET);
- }
-
- /* Headphone Detected */
- if ((micbits == DAC_FLAG_R1_NOMIC) || (hsbits)) {
- DBG(KERN_INFO "headphone\n");
- snd_soc_jack_report(aic3262->headset_jack,
- SND_JACK_HEADPHONE, SND_JACK_HEADSET);
- }
-
- /* Headset Detected - only with capless */
- if (micbits == DAC_FLAG_R1_MIC) {
- DBG(KERN_INFO "headset\n");
- snd_soc_jack_report(aic3262->headset_jack,
- SND_JACK_HEADSET, SND_JACK_HEADSET);
- }
- DBG(KERN_INFO "%s--\n", __func__);
- return IRQ_HANDLED;
-}
-
-/*
-* aic326x_headset_detect
-*
-* Call-back function called to check the status of Headset Pin.
-*/
-int aic326x_headset_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack, int jack_type)
-{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- aic3262->headset_jack = jack;
- /*Enable the Headset Interrupts*/
- snd_soc_write(codec, INT1_CNTL, 0x80);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(aic326x_headset_detect);
-
-int aic326x_headset_button_init(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack, int jack_type)
-{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
-
- aic3262->button_dev = input_allocate_device();
- aic3262->button_dev->name = "aic326x_headset_button";
- aic3262->button_dev->phys = "codec/input0";
- aic3262->button_dev->dev.parent = snd_card_get_device_link(codec->card->snd_card);
- input_set_capability(aic3262->button_dev, EV_KEY, KEY_MEDIA);
-
- if (input_register_device(aic3262->button_dev))
- {
- printk( "Unable to register input device headset button");
- }
+ aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- aic3262_jack_handler(aic3262->irq, codec);
return 0;
}
-#ifdef AIC3262_MULTI_I2S
-/*
-* aic3262_asi_default_config
-*
-* This function is used to perform the default pin configurations for
-* the functionalities which are specific to each ASI Port of the AIC3262
-* Audio Codec Chipset. The user is encouraged to change these values
-* if required on their platforms.
-*/
-static void aic3262_asi_default_config(struct snd_soc_codec *codec)
-{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
- u16 counter;
-
- DBG(KERN_INFO
- "#%s: Invoked. Will Config ASI Registers to Defaults..\n",
- __func__);
- for (counter = 0; counter < MAX_ASI_COUNT; counter++) {
- aic3262->asiCtxt[counter].asi_active = 0;
- aic3262->asiCtxt[counter].bclk_div = 1;
- aic3262->asiCtxt[counter].wclk_div = 1;
- aic3262->asiCtxt[counter].port_muted = 1;
- aic3262->asiCtxt[counter].bclk_div_option =
- BDIV_CLKIN_DAC_MOD_CLK;
- aic3262->asiCtxt[counter].offset1 = 0;
- aic3262->asiCtxt[counter].offset2 = 0;
- }
- /* ASI1 Defaults */
- aic3262->asiCtxt[0].bclk_output = ASI1_BCLK_DIVIDER_OUTPUT;
- aic3262->asiCtxt[0].wclk_output = GENERATED_DAC_FS;
- aic3262->asiCtxt[0].left_dac_output = DAC_PATH_LEFT;
- aic3262->asiCtxt[0].right_dac_output = DAC_PATH_LEFT;
- aic3262->asiCtxt[0].adc_input = ADC_PATH_MINIDSP_1;
- aic3262->asiCtxt[0].dout_option = ASI_OUTPUT;
-
- /* ASI2 Defaults */
- aic3262->asiCtxt[1].bclk_output = ASI2_BCLK_DIVIDER_OUTPUT;
- aic3262->asiCtxt[1].wclk_output = GENERATED_DAC_FS;
- aic3262->asiCtxt[1].left_dac_output = DAC_PATH_LEFT;
- aic3262->asiCtxt[1].right_dac_output = DAC_PATH_LEFT;
- aic3262->asiCtxt[1].adc_input = ADC_PATH_MINIDSP_2;
- aic3262->asiCtxt[1].dout_option = ASI_OUTPUT;
-
- /* ASI3 Defaults */
- aic3262->asiCtxt[2].bclk_output = ASI3_BCLK_DIVIDER_OUTPUT;
- aic3262->asiCtxt[2].wclk_output = GENERATED_DAC_FS;
- aic3262->asiCtxt[2].left_dac_output = DAC_PATH_LEFT;
- aic3262->asiCtxt[2].right_dac_output = DAC_PATH_LEFT;
- aic3262->asiCtxt[2].adc_input = ADC_PATH_MINIDSP_3;
- aic3262->asiCtxt[2].dout_option = ASI2_INPUT;
- return;
-}
-
-#endif /* #ifdef AIC3262_MULTI_I2S */
/*
*----------------------------------------------------------------------------
@@ -4125,402 +2203,223 @@ static void aic3262_asi_default_config(struct snd_soc_codec *codec)
*
*----------------------------------------------------------------------------
*/
-
-static int aic3262_probe(struct snd_soc_codec *codec)
+static int aic3262_codec_probe(struct snd_soc_codec *codec)
{
- struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
+ int ret_btn = 0;
+ struct aic3262 *control;
+ struct aic3262_priv *aic3262;
+ struct aic3262_jack_data *jack;
- DBG(KERN_INFO "#%s: Invoked..\n", __func__);
-
-#if defined(EN_REG_CACHE)
- codec->reg_cache =
- kmemdup(aic3262_reg, sizeof(aic3262_reg), GFP_KERNEL);
+ if (codec == NULL)
+ dev_err(codec->dev, "codec pointer is NULL.\n");
- if (!codec->reg_cache) {
- printk(KERN_ERR "aic3262: kmemdup failed\n");
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ control = codec->control_data;
+ aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL);
+ if (aic3262 == NULL)
return -ENOMEM;
- }
-#else
- /* Setting cache bypass - not to overwrite the cache registers,
- Codec registers have 4 pages which is not handled in the common
- cache code properly - bypass it in write value and save it
- using separate call*/
- codec->cache_bypass = 1;
-#endif
-#if defined(LOCAL_REG_ACCESS)
- codec->control_data = aic3262->control_data;
- codec->hw_write = (hw_write_t) aic3262_write__;
- codec->hw_read = aic3262_hw_read;
-#else
- ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
-#endif
- ret = reg_def_conf(codec);
- if (ret != 0) {
- printk(KERN_ERR "Failed to init TI codec: %d\n", ret);
- return ret;
+ snd_soc_codec_set_drvdata(codec, aic3262);
+ aic3262->pdata = dev_get_platdata(codec->dev->parent);
+ aic3262->codec = codec;
+ aic3262->cur_fw = NULL;
+ aic3262->isdefault_fw = 0;
+ aic3262->cfw_p = &(aic3262->cfw_ps);
+ aic3xxx_cfw_init(aic3262->cfw_p, &aic3262_cfw_codec_ops, aic3262);
+ aic3262->workqueue = create_singlethread_workqueue("aic3262-codec");
+ if (!aic3262->workqueue) {
+ ret = -ENOMEM;
+ goto work_err;
+ }
+ ret = device_create_file(codec->dev, &dev_attr_debug_level);
+ if (ret)
+ dev_info(codec->dev, "Failed to add debug_level sysfs\n");
+ INIT_DELAYED_WORK(&aic3262->delayed_work, aic3262_accessory_work);
+ mutex_init(&aic3262->mutex);
+ mutex_init(&codec->mutex);
+ mutex_init(&aic3262->cfw_mutex);
+ aic3262->dsp_runstate = 0;
+ /* use switch-class based headset reporting if platform requires it */
+ jack = &aic3262->hs_jack;
+ aic3262->idev = input_allocate_device();
+ if (aic3262->idev <= 0)
+ printk(KERN_ERR, "Allocate failed\n");
+
+ input_set_capability(aic3262->idev, EV_KEY, KEY_MEDIA);
+ ret = input_register_device(aic3262->idev);
+ if (ret < 0) {
+ dev_err(codec->dev, "register input dev fail\n");
+ goto input_dev_err;
}
- if (aic3262->irq) {
- /* audio interrupt */
- ret = request_threaded_irq(aic3262->irq, NULL,
- aic3262_jack_handler,
- IRQF_TRIGGER_FALLING,
- "tlv320aic3262", codec);
+ if (control->irq) {
+ ret = aic3262_request_irq(codec->control_data,
+ AIC3262_IRQ_HEADSET_DETECT,
+ aic3262_audio_handler, 0,
+ "aic3262_irq_headset", codec);
+
if (ret) {
- printk(KERN_INFO "#%s: IRQ Registration failed..[%d]",
- __func__, ret);
- dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
- return ret;
- } else
- DBG(KERN_INFO
- "#%s: irq Registration for IRQ %d done..\n",
- __func__, aic3262->irq);
- } else {
- DBG(KERN_INFO "#%s: I2C IRQ Configuration is Wrong. \
- Please check it..\n", __func__);
- }
+ dev_err(codec->dev, "HEADSET detect irq request"
+ "failed: %d\n", ret);
+ goto irq_err;
+ }
+
+ ret = aic3262_request_irq(codec->control_data,
+ AIC3262_IRQ_BUTTON_PRESS,
+ aic3262_button_handler, 0, "aic3262_irq_button",
+ codec);
- aic3262_asi_default_config(codec);
+ if (ret) {
+ dev_err(codec->dev, "button press irq request"
+ "failed: %d\n", ret);
+ goto irq_err;
+ }
+ }
+ /* Keep the reference voltage ON while in$
+ STANDBY mode for fast power up */
- /* off, with power on */
+ snd_soc_update_bits(codec, AIC3262_REF_PWR_DLY,
+ AIC3262_CHIP_REF_PWR_ON_MASK,
+ AIC3262_CHIP_REF_PWR_ON);
+ mdelay(40);
aic3262_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- ret = snd_soc_add_controls(codec, aic3262_snd_controls,
- ARRAY_SIZE(aic3262_snd_controls));
- if(ret)
- {
- printk(KERN_INFO "%s failed\n", __func__);
- }
+ aic3262->mute_asi = 0;
+
+ snd_soc_add_controls(codec, aic3262_snd_controls,
+ ARRAY_SIZE(aic3262_snd_controls));
aic3262_add_widgets(codec);
- /*TODO*/
- snd_soc_write(codec, MIC_BIAS_CNTL, 0x66);
#ifdef AIC3262_TiLoad
ret = aic3262_driver_init(codec);
if (ret < 0)
- printk(KERN_ERR
- "\nAIC3262 CODEC: aic3262_probe :TiLoad Initialization failed\n");
-#endif
-
-
-#ifdef CONFIG_MINI_DSP
- /* Program MINI DSP for ADC and DAC */
- aic3262_minidsp_program(codec);
- aic3262_add_minidsp_controls(codec);
- aic3262_change_book(codec, 0x0);
-#endif
-
-#ifdef MULTIBYTE_CONFIG_SUPPORT
- aic3262_add_multiconfig_controls(codec);
+ dev_err(codec->dev, "\nTiLoad Initialization failed\n");
#endif
+ /* force loading the default firmware */
+ aic3262_firmware_load(NULL, codec);
+ request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+ "tlv320aic3262_fw_v1.bin", codec->dev,
+ GFP_KERNEL, codec, aic3262_firmware_load);
- DBG(KERN_INFO "#%s: done..\n", __func__);
- return ret;
+ return 0;
+irq_err:
+ input_unregister_device(aic3262->idev);
+ input_free_device(aic3262->idev);
+input_dev_err:
+reg_err:
+work_err:
+ kfree(aic3262);
+ return 0;
}
-
-
/*
- *----------------------------------------------------------------------------
- * Function : aic3262_remove
- * Purpose : to remove aic3262 soc device
- *
- *----------------------------------------------------------------------------
- */
-static int aic3262_remove(struct snd_soc_codec *codec)
+* aic3262_remove: Cleans up and Remove aic3262 soc device
+* @codec: pointer variable to codec having informaton related to codec,
+*
+* Return: Return 0 on success.
+*/
+static int aic3262_codec_remove(struct snd_soc_codec *codec)
{
-
/* power down chip */
+ struct aic3262_priv *aic3262 = snd_soc_codec_get_drvdata(codec);
+ struct aic3262 *control = codec->control_data;
+ struct aic3262_jack_data *jack = &aic3262->hs_jack;
+
aic3262_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ /* free_irq if any */
+ switch (control->type) {
+ case TLV320AIC3262:
+ if (control->irq) {
+ aic3262_free_irq(control, AIC3262_IRQ_HEADSET_DETECT,
+ codec);
+ aic3262_free_irq(control, AIC3262_IRQ_BUTTON_PRESS,
+ codec);
+ }
+ break;
+ }
+ /* release firmware if any */
+ if (aic3262->cur_fw != NULL)
+ release_firmware(aic3262->cur_fw);
+ /* destroy workqueue for jac dev */
+ destroy_workqueue(aic3262->workqueue);
+ input_unregister_device(aic3262->idev);
+ input_free_device(aic3262->idev);
+
+ kfree(aic3262);
+
return 0;
}
-
-/*
- *----------------------------------------------------------------------------
- * @struct snd_soc_codec_device |
- * This structure is soc audio codec device sturecute which pointer
- * to basic functions aic3262_probe(), aic3262_remove(),
- * aic3262_suspend() and aic3262_resume()
- *----------------------------------------------------------------------------
- */
-static struct snd_soc_codec_driver soc_codec_dev_aic3262 = {
- .probe = aic3262_probe,
- .remove = aic3262_remove,
+static struct snd_soc_codec_driver soc_codec_driver_aic326x = {
+ .probe = aic3262_codec_probe,
+ .remove = aic3262_codec_remove,
.suspend = aic3262_suspend,
.resume = aic3262_resume,
+ .read = aic3262_codec_read,
+ .write = aic3262_codec_write,
.set_bias_level = aic3262_set_bias_level,
-#if defined(LOCAL_REG_ACCESS)
- .read = aic3262_read,
- .write = aic3262_write,
-#endif
-#if !defined(EN_REG_CACHE)
- .reg_cache_size = ARRAY_SIZE(aic3262_reg),
+ .reg_cache_size = 0,
.reg_word_size = sizeof(u8),
- .reg_cache_default = aic3262_reg,
-#endif
+ .reg_cache_default = NULL,
};
-
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_codec_probe
- * Purpose : This function attaches the i2c client and initializes
- * AIC3262 CODEC.
- * NOTE:
- * This function is called from i2c core when the I2C address is
- * valid.
- * If the i2c layer weren't so broken, we could pass this kind of
- * data around
- *
- *----------------------------------------------------------------------------
- */
-static __devinit int aic3262_codec_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+static int aic326x_probe(struct platform_device *pdev)
{
- int ret;
-
- struct aic3262_priv *aic3262;
-
- DBG(KERN_INFO "#%s: Entered\n", __func__);
-
- aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL);
-
- if (!aic3262) {
- printk(KERN_ERR "#%s: Unable to Allocate Priv struct..\n",
- __func__);
- return -ENOMEM;
- }
-
- i2c_set_clientdata(i2c, aic3262);
-#if defined(LOCAL_REG_ACCESS)
- aic3262->control_data = i2c;
-#endif
- aic3262->control_type = SND_SOC_I2C;
- aic3262->irq = i2c->irq;
- aic3262->pdata = i2c->dev.platform_data;
-
- /* The Configuration Support will be by default to 3 which
- * holds the MAIN Patch Configuration.
- */
- aic3262->current_dac_config[0] = -1;
- aic3262->current_dac_config[1] = -1;
- aic3262->current_adc_config[0] = -1;
- aic3262->current_adc_config[1] = -1;
-
- aic3262->mute_codec = 1;
-
- aic3262->page_no = 0;
- aic3262->book_no = 0;
- aic3262->active_count = 0;
- aic3262->dac_clkin_option = 3;
- aic3262->adc_clkin_option = 3;
-
- ret = snd_soc_register_codec(&i2c->dev,
- &soc_codec_dev_aic3262,
- tlv320aic3262_dai, ARRAY_SIZE(tlv320aic3262_dai));
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_driver_aic326x,
+ aic326x_dai_driver,
+ ARRAY_SIZE(aic326x_dai_driver));
- if (ret < 0)
- kfree(aic3262);
- DBG(KERN_INFO "#%s: Done ret %d\n", __func__, ret);
- return ret;
}
-/*
- *----------------------------------------------------------------------------
- * Function : aic3262_i2c_remove
- * Purpose : This function removes the i2c client and uninitializes
- * AIC3262 CODEC.
- * NOTE:
- * This function is called from i2c core
- * If the i2c layer weren't so broken, we could pass this kind of
- * data around
- *
- *----------------------------------------------------------------------------
- */
-static __devexit int aic3262_i2c_remove(struct i2c_client *i2c)
+static int aic326x_remove(struct platform_device *pdev)
{
- snd_soc_unregister_codec(&i2c->dev);
- kfree(i2c_get_clientdata(i2c));
+ snd_soc_unregister_codec(&pdev->dev);
return 0;
}
-static const struct i2c_device_id tlv320aic3262_id[] = {
- {"aic3262-codec", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, tlv320aic3262_id);
-
-static struct i2c_driver tlv320aic3262_i2c_driver = {
+static struct platform_driver aic326x_codec_driver = {
.driver = {
- .name = "aic3262-codec",
- .owner = THIS_MODULE,
- },
- .probe = aic3262_codec_probe,
- .remove = __devexit_p(aic3262_i2c_remove),
- .id_table = tlv320aic3262_id,
+ .name = "tlv320aic3262-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = aic326x_probe,
+ .remove = __devexit_p(aic326x_remove),
};
-#endif /*#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)*/
-
-#if defined(CONFIG_SPI_MASTER)
-static int aic3262_spi_write(struct spi_device *spi, const char *data, int len)
-{
- struct spi_transfer t;
- struct spi_message m;
- u8 msg[2];
-
- if (len <= 0)
- return 0;
-
- msg[0] = data[0];
- msg[1] = data[1];
-
- spi_message_init(&m);
- memset(&t, 0, (sizeof t));
- t.tx_buf = &msg[0];
- t.len = len;
-
- spi_message_add_tail(&t, &m);
- spi_sync(spi, &m);
-
- return len;
-}
-
-#ifdef RUN_DELAYED_WORK
/*
- * This function forces any delayed work to be queued and run.
- */
-static int run_delayed_work(struct delayed_work *dwork)
-{
- int ret;
-
- /* cancel any work waiting to be queued. */
- ret = cancel_delayed_work(dwork);
-
- /* if there was any work waiting then we run it now and
- * wait for it's completion */
- if (ret) {
- schedule_delayed_work(dwork, 0);
- flush_scheduled_work();
- }
- return ret;
-}
-#endif
-
-static int __devinit aic3262_spi_probe(struct spi_device *spi)
-{
- int ret;
- struct snd_soc_codec *codec;
- struct aic3262_priv *aic3262;
- printk(KERN_INFO "%s entering\n",__func__);
- aic3262 = kzalloc(sizeof(struct aic3262_priv), GFP_KERNEL);
-
- if (!aic3262) {
- printk(KERN_ERR "#%s: Unable to Allocate Priv struct..\n",
- __func__);
- return -ENOMEM;
- }
- codec = &aic3262->codec;
- codec->control_data = spi;
- aic3262->control_type = SND_SOC_SPI;
- codec->hw_write = (hw_write_t)aic3262_spi_write;
- codec->dev = &spi->dev;
-
- aic3262->pdata = spi->dev.platform_data;
-
- /* The Configuration Support will be by default to 3 which
- * holds the MAIN Patch Configuration.
- */
- aic3262->current_dac_config[0] = -1;
- aic3262->current_dac_config[1] = -1;
- aic3262->current_adc_config[0] = -1;
- aic3262->current_adc_config[1] = -1;
-
- aic3262->mute_codec = 1;
-
- aic3262->page_no = 0;
- aic3262->book_no = 0;
- aic3262->active_count = 0;
- aic3262->dac_clkin_option = 3;
- aic3262->adc_clkin_option = 3;
- dev_set_drvdata(&spi->dev, aic3262);
- spi_set_drvdata(spi, aic3262);
- ret = snd_soc_register_codec(&spi->dev,
- &soc_codec_dev_aic3262,
- tlv320aic3262_dai, ARRAY_SIZE(tlv320aic3262_dai));
-
- if (ret < 0) {
- printk(KERN_INFO "%s codec registeration failed\n",__func__);
- kfree(aic3262);
- }
- else {
- printk(KERN_INFO "%s registered\n",__func__);
- }
- printk(KERN_INFO "#%s: Done ret %d\n", __func__, ret);
- return ret;
-}
-
-static int __devexit aic3262_spi_remove(struct spi_device *spi)
-{
- struct aic3262_priv *aic3262 = dev_get_drvdata(&spi->dev);
- aic3262_set_bias_level(&aic3262->codec, SND_SOC_BIAS_OFF);
- snd_soc_unregister_codec(&spi->dev);
- kfree(aic3262);
- aic3262_codec = NULL;
- return 0;
-
-}
-
-static struct spi_driver aic3262_spi_driver = {
- .driver = {
- .name = "aic3262-codec",
- .bus = &spi_bus_type,
- .owner = THIS_MODULE,
- },
- .probe = aic3262_spi_probe,
- .remove = __devexit_p(aic3262_spi_remove),
-};
-#endif
+*----------------------------------------------------------------------------
+* Function : tlv320aic3262_modinit
+* Purpose : module init function. First function to run.
+*
+*----------------------------------------------------------------------------
+*/
static int __init tlv320aic3262_modinit(void)
{
- int ret = 0;
- printk(KERN_INFO "In %s\n",__func__);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- ret = i2c_add_driver(&tlv320aic3262_i2c_driver);
- if (ret != 0)
- printk(KERN_ERR "Failed to register aic326x i2c driver %d\n",
- ret);
-#endif
-#if defined(CONFIG_SPI_MASTER)
- printk(KERN_INFO "Inside config_spi_master\n");
- ret = spi_register_driver(&aic3262_spi_driver);
- if (ret != 0)
- printk(KERN_ERR "Failed to register aic3262 SPI driver: %d\n", ret);
-#endif
- return ret;
-
+ return platform_driver_register(&aic326x_codec_driver);
}
module_init(tlv320aic3262_modinit);
+/*
+*----------------------------------------------------------------------------
+* Function : tlv320aic3262_exit
+* Purpose : module init function. First function to run.
+*
+*----------------------------------------------------------------------------
+*/
static void __exit tlv320aic3262_exit(void)
{
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
- i2c_del_driver(&tlv320aic3262_i2c_driver);
-#endif
+ platform_driver_unregister(&aic326x_codec_driver);
+
}
-module_exit(tlv320aic3262_exit);
+module_exit(tlv320aic3262_exit);
+MODULE_ALIAS("platform:tlv320aic3262-codec");
MODULE_DESCRIPTION("ASoC TLV320AIC3262 codec driver");
-MODULE_AUTHOR("Barani Prashanth<gvbarani@mistralsolutions.com>");
-MODULE_AUTHOR("Ravindra<ravindra@mistralsolutions.com>");
+MODULE_AUTHOR("Y Preetam Sashank Reddy ");
+MODULE_AUTHOR("Barani Prashanth ");
+MODULE_AUTHOR("Mukund Navada K <navada@ti.com>");
+MODULE_AUTHOR("Naren Vasanad <naren.vasanad@ti.com>");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic326x.h b/sound/soc/codecs/tlv320aic326x.h
index bfcbefc5c079..4a7d909cea74 100644
--- a/sound/soc/codecs/tlv320aic326x.h
+++ b/sound/soc/codecs/tlv320aic326x.h
@@ -1,8 +1,9 @@
/*
- * linux/sound/soc/codecs/tlv320aic3262.h
+ * linux/sound/soc/codecs/tlv320aic326x.h
*
+ * Copyright (C) 2011 TI Solutions Pvt Ltd.
*
- * Copyright (C) 2012 Texas Instruments, Inc.
+ * Based on sound/soc/codecs/tlv320aic3262.c
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,49 +13,44 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * History:
- * Rev 0.1 ASoC driver support 20-01-2011
+ * The TLV320AIC3262 is a flexible, low-power, low-voltage stereo audio
+ * codec with digital microphone inputs and programmable outputs.
*
- * The AIC3262 ASoC driver is ported for the codec AIC3262.
+ * History:
*
+ * Rev 0.1 ASoC driver support TI 20-01-2011
+ * The AIC325x ASoC driver is ported for the codec AIC3262.
+ * Rev 0.2 ASoC driver support TI 21-03-2011
+ * The AIC326x ASoC driver is updated for linux 2.6.32 Kernel.
+ * Rev 0.3 ASoC driver support TI 20-04-2011
+ * The AIC326x ASoC driver is ported to 2.6.35 omap4 kernel
*/
#ifndef _TLV320AIC3262_H
#define _TLV320AIC3262_H
-#include <linux/input.h>
+#include "aic3xxx_cfw.h"
+#include "aic3xxx_cfw_ops.h"
+#include <linux/switch.h>
+
#define AUDIO_NAME "aic3262"
#define AIC3262_VERSION "1.1"
-
-//#define AIC3262_ASI2_MASTER 1
+/* Macro to enable the inclusion of tiload kernel driver */
+#define AIC3262_TiLoad
+#undef AIC3262_SYNC_MODE
+
+/* #define AIC3262_ASI1_MASTER */
+#undef AIC3262_ASI1_MASTER
+/* #define AIC3262_ASI2_MASTER */
+#undef AIC3262_ASI2_MASTER
+/* #define AIC3262_ASI3_MASTER */
+#undef AIC3262_ASI3_MASTER
+/* Macro for McBsp master / slave configuration */
+#define AIC3262_MCBSP_SLAVE /*3262 master */
/* Enable this macro allow for different ASI formats */
-/*#define ASI_MULTI_FMT*/
#undef ASI_MULTI_FMT
-#define INT_FLAG2_BUTTN_PRESSBIT 0x20
-
-/* Enable register caching on write */
-#define EN_REG_CACHE 1
-
-//#define MULTIBYTE_CONFIG_SUPPORT
-
-/*Setting all codec reg/write locally*/
-/* This definition is added as the snd_ direct call are
-result some issue with cache. Common code doesnot support
-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
-
-
-/* Macro enables or disables support for miniDSP in the driver */
-/* Enable the AIC3262_TiLoad macro first before enabling these macros */
-//#define CONFIG_MINI_DSP
-/*#undef CONFIG_MINI_DSP*/
-
/* Enable or disable controls to have Input routing*/
-/*#define FULL_IN_CNTL */
#undef FULL_IN_CNTL
/* AIC3262 supported sample rate are 8k to 192k */
#define AIC3262_RATES SNDRV_PCM_RATE_8000_192000
@@ -64,27 +60,10 @@ page, so fix that before commenting this line*/
| SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
#define AIC3262_FREQ_12000000 12000000
-#define AIC3262_FREQ_12288000 12288000
+#define AIC3262_FREQ_19200000 19200000
#define AIC3262_FREQ_24000000 24000000
-
-/* Macro for enabling the Multi_I2S Support in Driver */
-#define AIC3262_MULTI_I2S 1
-
-/* Driver Debug Messages Enabled */
-//#define DEBUG
-
-#ifdef DEBUG
- #define DBG(x...) printk(x)
-#else
- #define DBG(x...)
-#endif
-
-/*Select the below macro to decide on the DAC master volume controls.
- *2 independent or one combined
- */
-/*#define DAC_INDEPENDENT_VOL*/
-#undef DAC_INDEPENDENT_VOL
-
+#define AIC3262_FREQ_38400000 38400000
+#define AIC3262_FREQ_12288000 12288000
/* Audio data word length = 16-bits (default setting) */
#define AIC3262_WORD_LEN_16BITS 0x00
#define AIC3262_WORD_LEN_20BITS 0x01
@@ -92,510 +71,79 @@ page, so fix that before commenting this line*/
#define AIC3262_WORD_LEN_32BITS 0x03
/* sink: name of target widget */
-#define AIC3262_WIDGET_NAME 0
+#define AIC3262_WIDGET_NAME 0
/* control: mixer control name */
-#define AIC3262_CONTROL_NAME
+#define AIC3262_CONTROL_NAME 1
/* source: name of source name */
-#define AIC3262_SOURCE_NAME 2
+#define AIC3262_SOURCE_NAME 2
/* D15..D8 aic3262 register offset */
-#define AIC3262_REG_OFFSET_INDEX 0
+#define AIC3262_REG_OFFSET_INDEX 0
/* D7...D0 register data */
-#define AIC3262_REG_DATA_INDEX 1
+#define AIC3262_REG_DATA_INDEX 1
/* Serial data bus uses I2S mode (Default mode) */
-#define AIC3262_I2S_MODE 0x00
-#define AIC3262_DSP_MODE 0x01
-#define AIC3262_RIGHT_JUSTIFIED_MODE 0x02
-#define AIC3262_LEFT_JUSTIFIED_MODE 0x03
+#define AIC3262_I2S_MODE 0x00
+#define AIC3262_DSP_MODE 0x01
+#define AIC3262_RIGHT_JUSTIFIED_MODE 0x02
+#define AIC3262_LEFT_JUSTIFIED_MODE 0x03
/* 8 bit mask value */
-#define AIC3262_8BITS_MASK 0xFF
+#define AIC3262_8BITS_MASK 0xFF
/* shift value for CLK_REG_3 register */
-#define CLK_REG_3_SHIFT 6
+#define CLK_REG_3_SHIFT 6
/* shift value for DAC_OSR_MSB register */
-#define DAC_OSR_MSB_SHIFT 4
+#define DAC_OSR_MSB_SHIFT 4
/* number of codec specific register for configuration */
-#define NO_FEATURE_REGS 2
-
-/* Total number of ASI Ports */
-#define MAX_ASI_COUNT 3
-
+#define NO_FEATURE_REGS 2
/* AIC3262 register space */
/* Updated from 256 to support Page 3 registers */
-#define AIC3262_CACHEREGNUM 1024
-#define BIT7 (0x01 << 7)
-#define BIT6 (0x01 << 6)
-#define BIT5 (0x01 << 5)
-#define BIT4 (0x01 << 4)
-#define BIT3 (0x01 << 3)
-#define BIT2 (0x01 << 2)
-#define BIT1 (0x01 << 1)
-#define BIT0 (0x01 << 0)
-
-#define DAC_FLAG_MIC_MASKBITS 0x30
-#define DAC_FLAG_HS_MASKBITS 0x03
-#define DAC_FLAG_R1_NOJACK 0
-#define DAC_FLAG_R1_NOMIC (0x1 << 4)
-#define DAC_FLAG_R1_MIC (0x3 << 4)
-#define DAC_FLAG_R1_NOHS 0
-#define DAC_FLAG_R1_MONOHS 1
-#define DAC_FLAG_R1_STEREOHS 2
-
-/*mask patterns for DAC and ADC polling logic*/
-#define LDAC_POW_FLAG_MASK 0x80
-#define RDAC_POW_FLAG_MASK 0x08
-#define LADC_POW_FLAG_MASK 0x40
-#define RADC_POW_FLAG_MASK 0x04
-
-/* ****************** Book 0 Registers **************************************/
-
-/* ****************** Page 0 Registers **************************************/
-
-#define PAGE_SEL_REG 0
-#define RESET_REG 1
-#define DAC_ADC_CLKIN_REG 4
-#define PLL_CLKIN_REG 5
-#define PLL_CLK_RANGE_REG 5
-#define PLL_PR_POW_REG 6
-#define PLL_J_REG 7
-#define PLL_D_MSB 8
-#define PLL_D_LSB 9
-#define PLL_CKIN_DIV 10
-
-#define NDAC_DIV_POW_REG 11
-#define MDAC_DIV_POW_REG 12
-#define DOSR_MSB_REG 13
-#define DOSR_LSB_REG 14
-
-#define NADC_DIV_POW_REG 18
-#define MADC_DIV_POW_REG 19
-#define AOSR_REG 20
-#define CLKOUT_MUX 21
-#define CLKOUT_MDIV_VAL 22
-#define TIMER_REG 23
-
-#define LF_CLK_CNTL 24
-#define HF_CLK_CNTL_R1 25
-#define HF_CLK_CNTL_R2 26
-#define HF_CLK_CNTL_R3 27
-#define HF_CLK_CNTL_R4 28
-#define HF_CLK_TRIM_R1 29
-#define HF_CLK_TRIM_R2 30
-#define HF_CLK_TRIM_R3 31
-#define HF_CLK_TRIM_R4 32
-#define ADC_FLAG_R1 36
-#define DAC_FLAG_R1 37
-#define DAC_FLAG_R2 38
-
-#define STICKY_FLAG1 42
-#define INT_FLAG1 43
-#define STICKY_FLAG2 44
-#define STICKY_FLAG3 45
-#define INT_FLAG2 46
-#define INT1_CNTL 48
-#define INT2_CNTL 49
-#define INT_FMT 51
-
-#define DAC_PRB 60
-#define ADC_PRB 61
-#define PASI_DAC_DP_SETUP 63
-#define DAC_MVOL_CONF 64
-#define DAC_LVOL 65
-#define DAC_RVOL 66
-#define HP_DETECT 67
-#define DRC_CNTL_R1 68
-#define DRC_CNTL_R2 69
-#define DRC_CNTL_R3 70
-#define BEEP_CNTL_R1 71
-#define BEEP_CNTL_R2 72
-
-#define ADC_CHANNEL_POW 81
-#define ADC_FINE_GAIN 82
-#define LADC_VOL 83
-#define RADC_VOL 84
-#define ADC_PHASE 85
+#define AIC3262_CACHEREGNUM 1024
-#define LAGC_CNTL 86
-#define LAGC_CNTL_R2 87
-#define LAGC_CNTL_R3 88
-#define LAGC_CNTL_R4 89
-#define LAGC_CNTL_R5 90
-#define LAGC_CNTL_R6 91
-#define LAGC_CNTL_R7 92
-#define LAGC_CNTL_R8 93
+#define DSP_NON_SYNC_MODE(state) (!((state & 0x03) && (state & 0x30)))
-#define RAGC_CNTL 94
-#define RAGC_CNTL_R2 95
-#define RAGC_CNTL_R3 96
-#define RAGC_CNTL_R4 97
-#define RAGC_CNTL_R5 98
-#define RAGC_CNTL_R6 99
-#define RAGC_CNTL_R7 100
-#define RAGC_CNTL_R8 101
-#define MINIDSP_ACCESS_CTRL 121
-/* ****************** Page 1 Registers **************************************/
-#define PAGE_1 128
-
-#define POWER_CONF (PAGE_1 + 1)
-#define LDAC_PTM (PAGE_1 + 3)
-#define RDAC_PTM (PAGE_1 + 4)
-#define CM_REG (PAGE_1 + 8)
-#define HP_CTL (PAGE_1 + 9)
-#define HP_DEPOP (PAGE_1 + 11)
-#define RECV_DEPOP (PAGE_1 + 12)
-#define MA_CNTL (PAGE_1 + 17)
-#define LADC_PGA_MAL_VOL (PAGE_1 + 18)
-#define RADC_PGA_MAR_VOL (PAGE_1 + 19)
-
-
-#define LINE_AMP_CNTL_R1 (PAGE_1 + 22)
-#define LINE_AMP_CNTL_R2 (PAGE_1 + 23)
-
-#define HP_AMP_CNTL_R1 (PAGE_1 + 27)
-#define HP_AMP_CNTL_R2 (PAGE_1 + 28)
-#define HP_AMP_CNTL_R3 (PAGE_1 + 29)
-
-#define HPL_VOL (PAGE_1 + 31)
-#define HPR_VOL (PAGE_1 + 32)
-#define INT1_SEL_L (PAGE_1 + 34)
-#define RAMP_CNTL_R1 (PAGE_1 + 36)
-#define RAMP_CNTL_R2 (PAGE_1 + 37)
-//#define INT1_SEL_RM (PAGE_1 + 39)
-#define IN1L_SEL_RM (PAGE_1 + 39)
-#define IN1R_SEL_RM (PAGE_1 + 39)
-
-#define REC_AMP_CNTL_R5 (PAGE_1 + 40)
-#define RAMPR_VOL (PAGE_1 + 41)
-#define RAMP_TIME_CNTL (PAGE_1 + 42)
-#define SPK_AMP_CNTL_R1 (PAGE_1 + 45)
-#define SPK_AMP_CNTL_R2 (PAGE_1 + 46)
-#define SPK_AMP_CNTL_R3 (PAGE_1 + 47)
-#define SPK_AMP_CNTL_R4 (PAGE_1 + 48)
-#define MIC_BIAS_CNTL (PAGE_1 + 51)
-
-#define LMIC_PGA_PIN (PAGE_1 + 52)
-#define LMIC_PGA_PM_IN4 (PAGE_1 + 53)
-#define LMIC_PGA_MIN (PAGE_1 + 54)
-#define RMIC_PGA_PIN (PAGE_1 + 55)
-#define RMIC_PGA_PM_IN4 (PAGE_1 + 56)
-#define RMIC_PGA_MIN (PAGE_1 + 57)
-/* MIC PGA Gain Registers */
-#define MICL_PGA (PAGE_1 + 59)
-#define MICR_PGA (PAGE_1 + 60)
-#define HEADSET_TUNING1_REG (PAGE_1 + 119)
-#define HEADSET_TUNING2_REG (PAGE_1 + 120)
-#define MIC_PWR_DLY (PAGE_1 + 121)
-#define REF_PWR_DLY (PAGE_1 + 122)
-
-/* ****************** Page 4 Registers **************************************/
-#define PAGE_4 512
-#define ASI1_BUS_FMT (PAGE_4 + 1)
-#define ASI1_LCH_OFFSET (PAGE_4 + 2)
-#define ASI1_RCH_OFFSET (PAGE_4 + 3)
-#define ASI1_CHNL_SETUP (PAGE_4 + 4)
-#define ASI1_MULTI_CH_SETUP_R1 (PAGE_4 + 5)
-#define ASI1_MULTI_CH_SETUP_R2 (PAGE_4 + 6)
-#define ASI1_ADC_INPUT_CNTL (PAGE_4 + 7)
-#define ASI1_DAC_OUT_CNTL (PAGE_4 + 8)
-#define ASI1_ADC_OUT_TRISTATE (PAGE_4 + 9)
-#define ASI1_BWCLK_CNTL_REG (PAGE_4 + 10)
-#define ASI1_BCLK_N_CNTL (PAGE_4 + 11)
-#define ASI1_BCLK_N (PAGE_4 + 12)
-#define ASI1_WCLK_N (PAGE_4 + 13)
-#define ASI1_BWCLK_OUT_CNTL (PAGE_4 + 14)
-#define ASI1_DATA_OUT (PAGE_4 + 15)
-#define ASI2_BUS_FMT (PAGE_4 + 17)
-#define ASI2_LCH_OFFSET (PAGE_4 + 18)
-#define ASI2_RCH_OFFSET (PAGE_4 + 19)
-#define ASI2_ADC_INPUT_CNTL (PAGE_4 + 23)
-#define ASI2_DAC_OUT_CNTL (PAGE_4 + 24)
-#define ASI2_BWCLK_CNTL_REG (PAGE_4 + 26)
-#define ASI2_BCLK_N_CNTL (PAGE_4 + 27)
-#define ASI2_BCLK_N (PAGE_4 + 28)
-#define ASI2_WCLK_N (PAGE_4 + 29)
-#define ASI2_BWCLK_OUT_CNTL (PAGE_4 + 30)
-#define ASI2_DATA_OUT (PAGE_4 + 31)
-#define ASI3_BUS_FMT (PAGE_4 + 33)
-#define ASI3_LCH_OFFSET (PAGE_4 + 34)
-#define ASI3_RCH_OFFSET (PAGE_4 + 35)
-#define ASI3_ADC_INPUT_CNTL (PAGE_4 + 39)
-#define ASI3_DAC_OUT_CNTL (PAGE_4 + 40)
-#define ASI3_BWCLK_CNTL_REG (PAGE_4 + 42)
-#define ASI3_BCLK_N_CNTL (PAGE_4 + 43)
-#define ASI3_BCLK_N (PAGE_4 + 44)
-#define ASI3_WCLK_N (PAGE_4 + 45)
-#define ASI3_BWCLK_OUT_CNTL (PAGE_4 + 46)
-#define ASI3_DATA_OUT (PAGE_4 + 47)
-#define WCLK1_PIN_CNTL_REG (PAGE_4 + 65)
-#define DOUT1_PIN_CNTL_REG (PAGE_4 + 67)
-#define DIN1_PIN_CNTL_REG (PAGE_4 + 68)
-#define WCLK2_PIN_CNTL_REG (PAGE_4 + 69)
-#define BCLK2_PIN_CNTL_REG (PAGE_4 + 70)
-#define DOUT2_PIN_CNTL_REG (PAGE_4 + 71)
-#define DIN2_PIN_CNTL_REG (PAGE_4 + 72)
-#define WCLK3_PIN_CNTL_REG (PAGE_4 + 73)
-#define BCLK3_PIN_CNTL_REG (PAGE_4 + 74)
-#define DOUT3_PIN_CNTL_REG (PAGE_4 + 75)
-#define DIN3_PIN_CNTL_REG (PAGE_4 + 76)
-#define MCLK2_PIN_CNTL_REG (PAGE_4 + 82)
-#define GPIO1_IO_CNTL (PAGE_4 + 86)
-#define GPIO2_IO_CNTL (PAGE_4 + 87)
-#define GPI1_EN (PAGE_4 + 91)
-#define GPO2_EN (PAGE_4 + 92)
-#define GPO1_PIN_CNTL (PAGE_4 + 96)
-#define MINIDSP_PORT_CNTL_REG (PAGE_4 + 118)
-
-/****************************************************************************
-* Mixer control related #defines
-***************************************************************************
-*/
-#define WCLK1_ENUM 0
-#define DOUT1_ENUM 1
-#define DIN1_ENUM 2
-#define WCLK2_ENUM 3
-#define BCLK2_ENUM 4
-#define DOUT2_ENUM 5
-#define DIN2_ENUM 6
-#define WCLK3_ENUM 7
-#define BCLK3_ENUM 8
-#define DOUT3_ENUM 9
-#define DIN3_ENUM 10
-#define CLKIN_ENUM 11
-/*
-*****************************************************************************
-* Enumeration Definitions
-*****************************************************************************
-*/
-/* The below enumeration lists down all the possible inputs to the
-* the PLL of the AIC3262. The Private structure will hold a member
-* of this Enumeration Type.
-*/
-enum AIC3262_PLL_OPTION {
- PLL_CLKIN_MCLK1 = 0, /* 0000: (Device Pin) */
- PLL_CLKIN_BLKC1, /* 0001: (Device Pin) */
- PLL_CLKIN_GPIO1, /* 0010: (Device Pin)*/
- PLL_CLKIN_DIN1, /* 0011: (Device Pin)*/
- PLL_CLKIN_BCLK2, /* 0100: (Device Pin)*/
- PLL_CLKIN_GPI1, /* 0101: (Device Pin)*/
- PLL_CLKIN_HF_REF_CLK, /* 0110: (Device Pin)*/
- PLL_CLKIN_GPIO2, /* 0111: (Device Pin)*/
- PLL_CLKIN_GPI2, /* 1000: (Device Pin)*/
- PLL_CLKIN_MCLK2 /* 1001: (Device Pin)*/
-};
+#define TIME_DELAY 5
+#define DELAY_COUNTER 100
-/* ASI Specific Bit Clock Divider Input Options.
-* Please refer to Page 4 Reg 11, Reg 27 and Reg 43
-*/
-enum ASI_BDIV_CLKIN_OPTION {
- BDIV_CLKIN_DAC_CLK = 0, /* 00 DAC_CLK */
- BDIV_CLKIN_DAC_MOD_CLK, /* 01 DAC_MOD_CLK */
- BDIV_CLKIN_ADC_CLK, /* 02 ADC_CLK */
- BDIV_CLKIN_ADC_MOD_CLK /* 03 ADC_MOD_CLK */
-};
-
-/* ASI Specific Bit Clock Output Mux Options.
-* Please refer to Page 4 Reg 14, Reg 30 and Reg 46
-* Please note that we are not handling the Reserved
-* cases here.
-*/
-enum ASI_BCLK_OPTION {
- ASI1_BCLK_DIVIDER_OUTPUT = 0, /* 00 ASI1 Bit Clock Divider Output */
- ASI1_BCLK_INPUT, /* 01 ASI1 Bit Clock Input */
- ASI2_BCLK_DIVIDER_OUTPUT, /* 02 ASI2 Bit Clock Divider Output */
- ASI2_BCLK_INPUT, /* 03 ASI2 Bit Clock Input */
- ASI3_BCLK_DIVIDER_OUTPUT, /* 04 ASI3 Bit Clock Divider Output */
- ASI3_BBCLK_INPUT /* 05 ASi3 Bit Clock Input */
-};
-
-/* Above bits are to be configured after Shifting 4 bits */
-#define AIC3262_ASI_BCLK_MUX_SHIFT 4
-#define AIC3262_ASI_BCLK_MUX_MASK (BIT6 | BIT5 | BIT4)
-#define AIC3262_ASI_WCLK_MUX_MASK (BIT2 | BIT1 | BIT0)
-
-/* ASI Specific Word Clock Output Mux Options */
-enum ASI_WCLK_OPTION {
- GENERATED_DAC_FS = 0, /* 00 WCLK = DAC_FS */
- GENERATED_ADC_FS = 1, /* 01 WCLK = ADC_FS */
- ASI1_WCLK_DIV_OUTPUT = 2, /* 02 WCLK = ASI1 WCLK_DIV_OUT */
- ASI1_WCLK_INPUT = 3, /* 03 WCLK = ASI1 WCLK Input */
- ASI2_WCLK_DIV_OUTPUT = 4, /* 04 WCLK = ASI2 WCLK_DIV_OUT */
- ASI2_WCLK_INPUT = 5, /* 05 WCLK = ASI2 WCLK Input */
- ASI3_WCLK_DIV_OUTPUT = 6, /* 06 WCLK = ASI3 WCLK_DIV_OUT */
- ASI3_WCLK_INPUT = 7 /* 07 WCLK = ASI3 WCLK Input */
-};
-
-/* ASI DAC Output Control Options */
-enum ASI_DAC_OUTPUT_OPTION {
- DAC_PATH_OFF = 0, /* 00 DAC Datapath Off */
- DAC_PATH_LEFT, /* 01 DAC Datapath left Data */
- DAC_PATH_RIGHT, /* 02 DAC Datapath Right Data */
-};
-
-#define AIC3262_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5))
-#define AIC3262_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
-
-/* Shift the above options by so many bits */
-#define AIC3262_ASI_LDAC_PATH_SHIFT 6
-#define AIC3262_ASI_LDAC_PATH_MASK (BIT5 | BIT4)
-#define AIC3262_ASI_RDAC_PATH_SHIFT 4
-#define AIC3262_ASI_RDAC_PATH_MASK (BIT7 | BIT6)
-
-
-#define DAC_LR_MUTE_MASK 0xc
-#define DAC_LR_MUTE 0xc
-#define ENABLE_CLK_MASK 0x80
-#define ENABLE_CLK 0x80
-
-/* ASI specific ADC Input Control Options */
-enum ASI_ADC_INPUT_OPTION {
- ADC_PATH_OFF = 0, /* 00 ASI Digital Output Disabled */
- ADC_PATH_MINIDSP_1, /* 01 ASI Digital O/P from miniDSP_A(L1,R1) */
- ADC_PATH_ASI1, /* 02 ASI Digital Output from ASI1 */
- ADC_PATH_ASI2, /* 03 ASI Digital Output from ASI2 */
- ADC_PATH_ASI3, /* 04 ASI Digital Output from ASI3 */
- ADC_PATH_MINIDSP_2, /* 05 ASI Digital O/P from miniDSP_A(L2,R2) */
- ADC_PATH_MINIDSP_3 /* 05 ASI Digital O/P from miniDSP_A(L3,R3) */
-};
-
-/* ASI Specific DOUT Pin Options */
-enum ASI_DOUT_OPTION {
- ASI_OUTPUT = 0, /* 00 Default ASI Output */
- ASI1_INPUT, /* 01 ASI1 Data Input */
- ASI2_INPUT, /* 02 ASI2 Data Input */
- ASI3_INPUT /* 03 ASI3 Data Input */
-};
-
-#define AIC3262_ASI_DOUT_MASK (BIT1 | BIT0)
-
-/*
- *****************************************************************************
- * Structures Definitions
- *****************************************************************************
- */
-#define AIC3262_MULTI_ASI_ACTIVE(x) (((x)->asiCtxt[0].asi_active) || \
- ((x)->asiCtxt[1].asi_active) || \
- ((x)->asiCtxt[2].asi_active))
-
-/*
-*----------------------------------------------------------------------------
-* @struct aic3262_setup_data |
-* i2c specific data setup for AIC3262.
-* @field unsigned short |i2c_address |
-* Unsigned short for i2c address.
-*----------------------------------------------------------------------------
-*/
- struct aic3262_setup_data {
- unsigned short i2c_address;
-};
+#ifdef AIC3262_TiLoad
+int aic3262_driver_init(struct snd_soc_codec *codec);
+#endif
-/*
-*----------------------------------------------------------------------------
-* @struct aic3262_asi_data
-* ASI specific data stored for each ASI Interface
-*
-*
-*---------------------------------------------------------------------------
-*/
-struct aic3262_asi_data {
- u8 asi_active; /* ASI Active Flag */
- u8 master; /* Frame Master */
- u32 sampling_rate; /* Sampling Rate */
- enum ASI_BDIV_CLKIN_OPTION bclk_div_option; /* BCLK DIV Mux Option*/
- enum ASI_BCLK_OPTION bclk_output; /* BCLK Output Option*/
- enum ASI_WCLK_OPTION wclk_output; /* WCLK Output Option*/
- u8 bclk_div; /* BCLK Divider */
- u8 wclk_div; /* WCLK Divider */
- enum ASI_DAC_OUTPUT_OPTION left_dac_output; /* LDAC Path */
- enum ASI_DAC_OUTPUT_OPTION right_dac_output; /* RDAC Path */
- enum ASI_ADC_INPUT_OPTION adc_input; /* ADC Input Control */
- enum ASI_DOUT_OPTION dout_option; /* DOUT Option */
- u8 playback_mode; /* Playback Selected */
- u8 capture_mode; /* Record Selected */
- u8 port_muted; /* ASI Muted */
- u8 pcm_format; /* PCM Format */
- u8 word_len; /* Word Length */
- u8 offset1; /* Left Ch offset */
- u8 offset2; /* Right Ch Offset */
+struct aic3262_jack_data {
+ struct snd_soc_jack *jack;
+ int report;
+ struct switch_dev sdev;
};
-/*
-*----------------------------------------------------------------------------
-* @struct aic3262_priv |
-* AIC3262 priviate data structure to set the system clock, mode and
-* page number.
-* @field u32 | sysclk |
-* system clock
-* @field s32 | master |
-* master/slave mode setting for AIC3262
-* @field u8 | book_no |
-* book number.
-* @field u8 | page_no |
-* page number. Here, page 0 and page 1 are used.
-*----------------------------------------------------------------------------
-*/
struct aic3262_priv {
- enum snd_soc_control_type control_type;
- struct aic326x_pdata *pdata;
- struct snd_soc_codec codec;
u32 sysclk;
s32 master;
- u8 book_no;
- u8 page_no;
- u8 process_flow;
- u8 mute_codec;
u8 stream_status;
- u32 active_count;
- int current_dac_config[MAX_ASI_COUNT];
- int current_adc_config[MAX_ASI_COUNT];
- int current_config;
- struct aic3262_asi_data asiCtxt[MAX_ASI_COUNT];
- enum AIC3262_PLL_OPTION aic3262_pllclkin_option;
- u8 dac_clkin_option;
- u8 adc_clkin_option;
- int irq;
- u8 dac_reg;
- u8 adc_gain;
- u8 hpl;
- u8 hpr;
- u8 rec_amp;
- u8 rampr;
- u8 spk_amp;
- struct spi_device *spi;
- struct snd_soc_jack *headset_jack;
- struct input_dev *button_dev;
- int codec_audio_mode;
-#if defined(LOCAL_REG_ACCESS)
- void *control_data;
-#endif
-};
-
-/*
- *----------------------------------------------------------------------------
- * @struct aic3262_configs |
- * AIC3262 initialization data which has register offset and register
- * value.
- * @field u8 | book_no |
- * AIC3262 Book Number Offsets required for initialization..
- * @field u16 | reg_offset |
- * AIC3262 Register offsets required for initialization..
- * @field u8 | reg_val |
- * value to set the AIC3262 register to initialize the AIC3262.
- *----------------------------------------------------------------------------
- */
-struct aic3262_configs {
- u8 book_no;
- u16 reg_offset;
- u8 reg_val;
+ struct aic3262_jack_data hs_jack;
+ struct workqueue_struct *workqueue;
+ struct delayed_work delayed_work;
+ struct input_dev *idev;
+ struct snd_soc_codec *codec;
+ struct mutex mutex;
+ struct mutex cfw_mutex;
+ struct cfw_state cfw_ps;
+ struct cfw_state *cfw_p;
+ struct aic3262_pdata *pdata;
+ int mute_asi; /* Bit 0 -> ASI1, Bit 1-> ASI2, Bit 2 -> ASI3 */
+ int asi_fmt[2];
+ int dsp_runstate;
+ struct firmware *cur_fw;
+ int isdefault_fw;
};
/*
*----------------------------------------------------------------------------
* @struct aic3262_rate_divs |
* Setting up the values to get different freqencies
+ *
* @field u32 | mclk |
* Master clock
* @field u32 | rate |
@@ -620,8 +168,6 @@ struct aic3262_configs {
* value for madc
* @field u32 | blck_N |
* value for block N
- * @field u32 | aic3262_configs |
- * configurations for aic3262 register value
*----------------------------------------------------------------------------
*/
struct aic3262_rate_divs {
@@ -637,49 +183,16 @@ struct aic3262_rate_divs {
u8 nadc;
u8 madc;
u8 blck_N;
- struct aic3262_configs codec_specific_regs[NO_FEATURE_REGS];
};
-/*
-*****************************************************************************
-* EXTERN DECLARATIONS
-*****************************************************************************
-*/
-/*
- *----------------------------------------------------------------------------
- * @func aic326x_headset_detect
- * This function help to setup the needed registers to
- * enable the headset detection
- *
- */
-extern int aic326x_headset_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack, int jack_type);
-extern int aic326x_headset_button_init(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack, int jack_type);
-
-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, 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);
-extern int reg_def_conf(struct snd_soc_codec *codec);
-extern int i2c_verify_book0(struct snd_soc_codec *codec);
-extern int poll_dac(struct snd_soc_codec *codec, int left_right, int on_off);
-extern int poll_adc(struct snd_soc_codec *codec, int left_right, int on_off);
-
-#ifdef CONFIG_MINI_DSP
-extern int aic3262_minidsp_program(struct snd_soc_codec *codec);
-extern int aic3262_add_minidsp_controls(struct snd_soc_codec *codec);
-#endif
-
-
-#ifdef MULTIBYTE_CONFIG_SUPPORT
-extern int aic3262_add_multiconfig_controls(struct snd_soc_codec *codec);
-#endif
+extern struct snd_soc_dai tlv320aic3262_dai;
+extern struct snd_soc_codec_device soc_codec_dev_aic3262;
+extern const struct aic3xxx_codec_ops aic3262_cfw_codec_ops;
+void aic3262_hs_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *jack, int report);
+unsigned int aic3262_read(struct snd_soc_codec *codec, unsigned int reg);
+int aic3262_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value);
#endif /* _TLV320AIC3262_H */
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index ef69f5a02709..db2e0f0c00e8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2897,6 +2897,7 @@ int snd_soc_register_card(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->list);
card->instantiated = 0;
mutex_init(&card->mutex);
+ mutex_init(&card->dapm_mutex);
mutex_lock(&client_mutex);
list_add(&card->list, &card_list);
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d67c637557a7..ffb6af574c7f 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -1719,7 +1719,12 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
*/
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
{
- return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ int ret;
+
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
+ ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
@@ -1882,15 +1887,18 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
{
int i, ret;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_add_route(dapm, route);
if (ret < 0) {
dev_err(dapm->dev, "Failed to add route %s->%s\n",
route->source, route->sink);
+ mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
@@ -1963,12 +1971,14 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
int i, err;
int ret = 0;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
err = snd_soc_dapm_weak_route(dapm, route);
if (err)
ret = err;
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
@@ -1987,6 +1997,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
struct snd_soc_dapm_widget *w;
unsigned int val;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
list_for_each_entry(w, &dapm->card->widgets, list)
{
if (w->new)
@@ -1996,8 +2008,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
w->kcontrols = kzalloc(w->num_kcontrols *
sizeof(struct snd_kcontrol *),
GFP_KERNEL);
- if (!w->kcontrols)
+ if (!w->kcontrols) {
+ mutex_unlock(&dapm->card->dapm_mutex);
return -ENOMEM;
+ }
}
switch(w->id) {
@@ -2060,6 +2074,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
}
dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2119,6 +2134,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
@@ -2145,7 +2161,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
/* old connection must be powered down */
connect = invert ? 1 : 0;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, reg, mask, val);
if (change) {
@@ -2167,7 +2183,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2216,6 +2232,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask, bitmask;
@@ -2236,7 +2253,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mask |= (bitmask - 1) << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2258,7 +2275,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2295,6 +2312,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value;
int change;
@@ -2304,7 +2322,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = widget->value != ucontrol->value.enumerated.item[0];
if (change) {
@@ -2318,7 +2336,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2383,6 +2401,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask;
@@ -2401,7 +2420,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
mask |= e->mask << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2423,7 +2442,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2458,14 +2477,15 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = codec->card;
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
ucontrol->value.integer.value[0] =
snd_soc_dapm_get_pin_status(&codec->dapm, pin);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
@@ -2481,19 +2501,19 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_card *card = codec->card;
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
if (ucontrol->value.integer.value[0])
snd_soc_dapm_enable_pin(&codec->dapm, pin);
else
snd_soc_dapm_disable_pin(&codec->dapm, pin);
- snd_soc_dapm_sync(&codec->dapm);
-
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
+ snd_soc_dapm_sync(&codec->dapm);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2561,16 +2581,19 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
{
int i, ret;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_new_control(dapm, widget);
if (ret < 0) {
dev_err(dapm->dev,
"ASoC: Failed to create DAPM control %s: %d\n",
widget->name, ret);
+ mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
widget++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
@@ -2621,13 +2644,14 @@ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
const char *stream, int event)
{
struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = rtd->card;
if (stream == NULL)
return 0;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_PCM);
soc_dapm_stream_event(&codec->dapm, stream, event);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index d3d549a907a4..594c963cb8ea 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -37,7 +37,7 @@ snd-soc-tegra-max98088-objs := tegra_max98088.o
snd-soc-tegra-aic326x-objs := tegra_aic326x.o
snd-soc-tegra-rt5640-objs := tegra_rt5640.o
snd-soc-tegra-max98095-objs := tegra_max98095.o
-snd-soc-tegra-p1852-objs := tegra_p1852.o
+snd-soc-tegra-vcm-objs := tegra_vcm.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
obj-$(CONFIG_SND_SOC_TEGRA_COLIBRI_T20) += snd-soc-tegra-colibri_t20.o
@@ -48,4 +48,5 @@ obj-$(CONFIG_SND_SOC_TEGRA_MAX98088) += snd-soc-tegra-max98088.o
obj-$(CONFIG_SND_SOC_TEGRA_TLV320AIC326X) += snd-soc-tegra-aic326x.o
obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
obj-$(CONFIG_SND_SOC_TEGRA_MAX98095) += snd-soc-tegra-max98095.o
-obj-$(CONFIG_SND_SOC_TEGRA_P1852) += snd-soc-tegra-p1852.o
+obj-$(CONFIG_SND_SOC_TEGRA_P1852) += snd-soc-tegra-vcm.o
+obj-$(CONFIG_SND_SOC_TEGRA_P852) += snd-soc-tegra-vcm.o
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index 72e64470008a..03ddff5e8b95 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -557,6 +557,13 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
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 I2S sync clock rate\n");
diff --git a/sound/soc/tegra/tegra_aic326x.c b/sound/soc/tegra/tegra_aic326x.c
index 4cacb6758eb8..de4a1457a7ae 100644
--- a/sound/soc/tegra/tegra_aic326x.c
+++ b/sound/soc/tegra/tegra_aic326x.c
@@ -8,6 +8,7 @@
*
* (c) 2010, 2011 Nvidia Graphics Pvt. Ltd.
*
+ * 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 published by the Free Software Foundation.
@@ -26,6 +27,7 @@
#include <asm/mach-types.h>
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -42,6 +44,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <linux/mfd/tlv320aic3262-registers.h>
#include "../codecs/tlv320aic326x.h"
@@ -274,8 +277,9 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk, sample_size, daifmt;
- int err;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, sample_size, i2s_daifmt;
+ int err, rate;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
#endif
@@ -294,9 +298,30 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream,
if (mclk < 0)
return mclk;
- daifmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
@@ -310,25 +335,29 @@ static int tegra_aic326x_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(codec_dai, daifmt);
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "codec_dai fmt not set\n");
return err;
}
- err = snd_soc_dai_set_fmt(cpu_dai, daifmt);
+ err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt);
if (err < 0) {
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);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
}
+ err = snd_soc_dai_set_pll(codec_dai, 0, AIC3262_PLL_CLKIN_MCLK1 , rate,
+ params_rate(params));
+
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
err = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAP_SEL_DAC1,
TEGRA20_DAS_DAP_ID_1);
@@ -390,7 +419,8 @@ static int tegra_aic326x_bt_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
- int err, srate, mclk, min_mclk, sample_size;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int err, srate, mclk, min_mclk, sample_size, i2s_daifmt;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(rtd->cpu_dai);
#endif
@@ -423,10 +453,32 @@ static int tegra_aic326x_bt_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(rtd->cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[BT_SCO].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
+ err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt);
if (err < 0) {
dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n");
@@ -624,7 +676,8 @@ static int tegra_aic326x_voice_call_hw_params(
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, rate, i2s_daifmt;
int err, pcmdiv, vxclkdiv;;
srate = params_rate(params);
@@ -632,6 +685,36 @@ static int tegra_aic326x_voice_call_hw_params(
if (mclk < 0)
return mclk;
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ if (machine_is_tegra_enterprise()) {
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev,
+ "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+ } else {
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ }
+
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
if (!(machine->util_data.set_mclk % mclk))
@@ -644,31 +727,29 @@ static int tegra_aic326x_voice_call_hw_params(
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- if(machine_is_tegra_enterprise()) {
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
- } else {
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_DSP_B |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
- }
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "codec_dai fmt not set\n");
return err;
}
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
}
- if(!machine_is_tegra_enterprise()) {
+ err = snd_soc_dai_set_pll(codec_dai, 0, AIC3262_PLL_CLKIN_MCLK1 , rate,
+ params_rate(params));
+
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai PLL clock not set\n");
+ return err;
+ }
+
+ if (!machine_is_tegra_enterprise()) {
if (params_rate(params) == 8000) {
/* Change these Settings for 8KHz*/
pcmdiv = 1;
@@ -691,14 +772,6 @@ static int tegra_aic326x_voice_call_hw_params(
/* codec configuration */
machine->codec_info[HIFI_CODEC].rate = params_rate(params);
machine->codec_info[HIFI_CODEC].channels = params_channels(params);
- machine->codec_info[HIFI_CODEC].bitsize = 16;
- machine->codec_info[HIFI_CODEC].is_i2smaster = 1;
- machine->codec_info[HIFI_CODEC].is_format_dsp = 0;
-
- /* baseband configuration */
- machine->codec_info[BASEBAND].bitsize = 16;
- machine->codec_info[BASEBAND].is_i2smaster = 1;
- machine->codec_info[BASEBAND].is_format_dsp = 1;
#endif
machine->is_device_bt = 0;
@@ -754,14 +827,6 @@ static int tegra_aic326x_bt_voice_call_hw_params(
/* codec configuration */
machine->codec_info[BT_SCO].rate = params_rate(params);
machine->codec_info[BT_SCO].channels = params_channels(params);
- machine->codec_info[BT_SCO].bitsize = 16;
- machine->codec_info[BT_SCO].is_i2smaster = 1;
- machine->codec_info[BT_SCO].is_format_dsp = 1;
-
- /* baseband configuration */
- machine->codec_info[BASEBAND].bitsize = 16;
- machine->codec_info[BASEBAND].is_i2smaster = 1;
- machine->codec_info[BASEBAND].is_format_dsp = 1;
#endif
machine->is_device_bt = 1;
@@ -836,7 +901,7 @@ enum headset_state {
static int aic326x_headset_switch_notify(struct notifier_block *self,
unsigned long action, void *dev)
{
- int state = 0;
+ int state = BIT_NO_HEADSET;
switch (action) {
case SND_JACK_HEADPHONE:
@@ -908,6 +973,7 @@ static const struct snd_soc_dapm_widget tegra_aic326x_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("Ext Mic"),
SND_SOC_DAPM_LINE("Linein", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_MIC("DMIC", NULL),
};
static const struct snd_soc_dapm_route aic326x_audio_map[] = {
@@ -922,10 +988,15 @@ static const struct snd_soc_dapm_route aic326x_audio_map[] = {
{"IN2L", NULL, "Mic Bias Int"},
{"Mic Bias Int" ,NULL, "Int Mic"},
{"IN2R", NULL, "Mic Bias Int"},
- {"Mic Bias Ext" ,NULL, "Mic Jack"},
- {"CM1L" ,NULL, "Mic Jack"},
{"IN1L", NULL, "Mic Bias Ext"},
- {"IN1L", NULL, "CM1L"},
+ {"Mic Bias Ext" ,NULL, "Mic Jack"},
+ /* Connect LDMIC and RDMIC to DMIC widget*/
+ {"Left DMIC", NULL, "Mic Bias Int"},
+ {"Right DMIC", NULL, "Mic Bias Int"},
+ {"Mic Bias Int", NULL, "Int Mic"},
+/* {"CM1L" ,NULL, "Mic Jack"}, */
+/* {"IN1L", NULL, "Mic Bias Ext"}, */
+/* {"IN1L", NULL, "CM1L"}, */
};
static const struct snd_kcontrol_new tegra_aic326x_controls[] = {
@@ -1052,7 +1123,8 @@ static int tegra_aic326x_init(struct snd_soc_pcm_runtime *rtd)
tegra_aic326x_hp_jack_pins);
#endif
- aic326x_headset_detect(codec, &tegra_aic326x_hp_jack,
+ /* update jack status during boot */
+ aic3262_hs_jack_detect(codec, &tegra_aic326x_hp_jack,
SND_JACK_HEADSET);
/* Add call mode switch control */
@@ -1066,9 +1138,9 @@ static int tegra_aic326x_init(struct snd_soc_pcm_runtime *rtd)
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);
+/* snd_soc_dapm_force_enable_pin(dapm, "Mic Bias Ext");
+ snd_soc_dapm_force_enable_pin(dapm,"Mic Bias Int");
+ snd_soc_dapm_sync(dapm); */
return 0;
}
@@ -1077,14 +1149,14 @@ static struct snd_soc_dai_link tegra_aic326x_dai[] = {
[DAI_LINK_HIFI] = {
.name = "AIC3262",
.stream_name = "AIC3262 PCM HIFI",
- .codec_name = "aic3262-codec.4-0018",
+ .codec_name = "tlv320aic3262-codec",
.platform_name = "tegra-pcm-audio",
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
.cpu_dai_name = "tegra20-i2s.0",
#else
.cpu_dai_name = "tegra30-i2s.0",
#endif
- .codec_dai_name = "aic3262-asi1",
+ .codec_dai_name = "aic326x-asi1",
.init = tegra_aic326x_init,
.ops = &tegra_aic326x_hifi_ops,
},
@@ -1118,10 +1190,10 @@ static struct snd_soc_dai_link tegra_aic326x_dai[] = {
[DAI_LINK_VOICE_CALL] = {
.name = "VOICE CALL",
.stream_name = "VOICE CALL PCM",
- .codec_name = "aic3262-codec.4-0018",
+ .codec_name = "tlv320aic3262-codec",
.platform_name = "tegra-pcm-audio",
.cpu_dai_name = "dit-hifi",
- .codec_dai_name = "aic3262-asi2",
+ .codec_dai_name = "aic326x-asi2",
.ops = &tegra_aic326x_voice_call_ops,
},
[DAI_LINK_BT_VOICE_CALL] = {
@@ -1183,11 +1255,23 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
#endif
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- for (i = 0; i < NUM_I2S_DEVICES ; i++)
- machine->codec_info[i].i2s_id = pdata->audio_port_id[i];
-
- machine->codec_info[BASEBAND].rate = pdata->baseband_param.rate;
- machine->codec_info[BASEBAND].channels = pdata->baseband_param.channels;
+ for (i = 0; i < NUM_I2S_DEVICES ; i++) {
+ machine->codec_info[i].i2s_id =
+ pdata->i2s_param[i].audio_port_id;
+ machine->codec_info[i].bitsize =
+ pdata->i2s_param[i].sample_size;
+ machine->codec_info[i].is_i2smaster =
+ pdata->i2s_param[i].is_i2s_master;
+ machine->codec_info[i].rate =
+ pdata->i2s_param[i].rate;
+ machine->codec_info[i].channels =
+ pdata->i2s_param[i].channels;
+ if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) ||
+ (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B))
+ machine->codec_info[i].is_format_dsp = 1;
+ else
+ machine->codec_info[i].is_format_dsp = 0;
+ }
tegra_aic326x_dai[DAI_LINK_HIFI].cpu_dai_name =
tegra_i2s_dai_name[machine->codec_info[HIFI_CODEC].i2s_id];
@@ -1196,10 +1280,10 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
tegra_i2s_dai_name[machine->codec_info[BT_SCO].i2s_id];
#endif
- if(machine_is_tegra_enterprise()) {
- tegra_aic326x_dai[DAI_LINK_HIFI].codec_name = "aic3262-codec.0-0018";
- tegra_aic326x_dai[DAI_LINK_VOICE_CALL].codec_name = "aic3262-codec.0-0018";
- tegra_aic326x_dai[DAI_LINK_VOICE_CALL].codec_dai_name = "aic3262-asi1";
+ if (machine_is_tegra_enterprise()) {
+ tegra_aic326x_dai[DAI_LINK_HIFI].codec_name = "tlv320aic3262-codec";
+ tegra_aic326x_dai[DAI_LINK_VOICE_CALL].codec_name = "tlv320aic3262-codec";
+ tegra_aic326x_dai[DAI_LINK_VOICE_CALL].codec_dai_name = "aic326x-asi1";
}
ret = snd_soc_register_card(card);
@@ -1214,6 +1298,16 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
goto err_unregister_card;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+#endif
+
return 0;
err_unregister_card:
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index 6ab5b2d46a1f..99ba90d9fc7b 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -2,8 +2,7 @@
* tegra_asoc_utils.c - Harmony machine ASoC driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
+ * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
@@ -87,8 +86,11 @@ static int tegra_set_avp_device(struct snd_kcontrol *kcontrol,
prtd = substream->runtime->private_data;
if (prtd->running)
return -EBUSY;
- if (prtd)
+ if (prtd) {
prtd->disable_intr = true;
+ if (data->avp_dma_addr || prtd->avp_dma_addr)
+ prtd->avp_dma_addr = data->avp_dma_addr;
+ }
}
}
data->avp_device_id = id;
@@ -122,6 +124,33 @@ static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol,
return 0;
}
+static int tegra_set_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;
+ struct tegra_runtime_data *prtd;
+
+ if (data->avp_device_id < 0)
+ return 0;
+
+ data->avp_dma_addr = ucontrol->value.integer.value[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)
+ return 0;
+
+ prtd->avp_dma_addr = data->avp_dma_addr;
+ return 1;
+}
+
static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -129,6 +158,7 @@ static int tegra_get_dma_addr(struct snd_kcontrol *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] = 0;
if (data->avp_device_id < 0)
@@ -139,7 +169,14 @@ static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol,
if (!substream || !substream->runtime)
return 0;
- ucontrol->value.integer.value[0] = substream->runtime->dma_addr;
+ prtd = substream->runtime->private_data;
+ if (!prtd || !prtd->dma_chan)
+ return 0;
+
+ ucontrol->value.integer.value[0] = prtd->avp_dma_addr ?
+ prtd->avp_dma_addr :
+ substream->runtime->dma_addr;
+
return 0;
}
@@ -149,7 +186,7 @@ struct snd_kcontrol_new tegra_avp_controls[] = {
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),
+ 0, tegra_get_dma_addr, tegra_set_dma_addr),
};
int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
@@ -342,28 +379,6 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
}
#endif
-#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
-#if TEGRA30_I2S_MASTER_PLAYBACK
- ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0);
- if (ret) {
- dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
- goto err_put_out1;
- }
-#else
- rate = clk_get_rate(data->clk_m);
-
- if(rate == 26000000)
- clk_set_rate(data->clk_cdev1, 13000000);
-
- ret = clk_set_parent(data->clk_cdev1, data->clk_m);
- if (ret) {
- dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
- goto err_put_out1;
- }
-#endif
-
-#endif
-
ret = clk_enable(data->clk_cdev1);
if (ret) {
dev_err(data->dev, "Can't enable clk cdev1/extern1");
@@ -402,6 +417,34 @@ err:
}
EXPORT_SYMBOL_GPL(tegra_asoc_utils_init);
+#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
+int tegra_asoc_utils_set_parent (struct tegra_asoc_utils_data *data,
+ int is_i2s_master)
+{
+ int ret = -ENODEV;
+
+ if (is_i2s_master) {
+ ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0);
+ if (ret) {
+ dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
+ return ret;
+ }
+ } else {
+ if(clk_get_rate(data->clk_m) == 26000000)
+ clk_set_rate(data->clk_cdev1, 13000000);
+
+ ret = clk_set_parent(data->clk_cdev1, data->clk_m);
+ if (ret) {
+ dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_parent);
+#endif
+
void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
{
if (!IS_ERR(data->clk_out1))
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 0423f02b76cc..cd137967fcb0 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -2,7 +2,7 @@
* tegra_asoc_utils.h - Definitions for Tegra DAS driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (c) 2010-12, 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
@@ -24,7 +24,6 @@
#define __TEGRA_ASOC_UTILS_H_
-#define TEGRA30_I2S_MASTER_PLAYBACK 1
#define TEGRA_ALSA_MAX_DEVICES 6
#define TEGRA_DMA_MAX_CHANNELS 32
@@ -44,14 +43,17 @@ struct tegra_asoc_utils_data {
int set_mclk;
int lock_count;
int avp_device_id;
+ unsigned int avp_dma_addr;
};
int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
- int mclk);
+ int mclk);
void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data,
- int lock);
+ int lock);
int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
- struct device *dev, struct snd_soc_card *card);
+ struct device *dev, struct snd_soc_card *card);
+int tegra_asoc_utils_set_parent(struct tegra_asoc_utils_data *data,
+ int is_i2s_master);
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);
diff --git a/sound/soc/tegra/tegra_max98088.c b/sound/soc/tegra/tegra_max98088.c
index 82c2b930a39e..88098fcd99d9 100644
--- a/sound/soc/tegra/tegra_max98088.c
+++ b/sound/soc/tegra/tegra_max98088.c
@@ -12,6 +12,7 @@
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
+ * 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 published by the Free Software Foundation.
@@ -213,14 +214,16 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
#endif
- int srate, mclk, sample_size, i2s_daifmt;
+ int srate, mclk, sample_size, i2s_daifmt, i2s_master;
int err;
- struct clk *clk;
int rate;
+ i2s_master = pdata->i2s_param[HIFI_CODEC].is_i2s_master;
+
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
sample_size = 16;
@@ -251,32 +254,31 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
break;
}
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= i2s_master ? SND_SOC_DAIFMT_CBS_CFS :
+ SND_SOC_DAIFMT_CBM_CFM;
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
- clk = clk_get_sys(NULL, "cdev1");
-#else
- clk = clk_get_sys("extern1", NULL);
-#endif
- if (IS_ERR(clk)) {
- dev_err(card->dev, "Can't retrieve clk cdev1\n");
- err = PTR_ERR(clk);
- return err;
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
}
- rate = clk_get_rate(clk);
- printk("extern1 rate=%d\n",rate);
-
-#if TEGRA30_I2S_MASTER_PLAYBACK
- i2s_daifmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
-#else
- i2s_daifmt = SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM;
- mclk = rate;
-#endif
-
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
if (!(machine->util_data.set_mclk % mclk))
@@ -289,7 +291,9 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(codec_dai,i2s_daifmt);
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "codec_dai fmt not set\n");
return err;
@@ -301,8 +305,17 @@ static int tegra_max98088_hw_params(struct snd_pcm_substream *substream,
return err;
}
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
+
+ /* ULP specific use case for 44.1kHz stream. */
+ if ((!i2s_master) && (srate == 44100) &&
+ machine_is_tegra_enterprise()) {
+ clk_set_rate(machine->util_data.clk_cdev1, (256 * srate));
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate,
+ SND_SOC_CLOCK_IN);
+ }
+
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
@@ -371,7 +384,9 @@ static int tegra_bt_hw_params(struct snd_pcm_substream *substream,
#endif
struct snd_soc_card *card = rtd->card;
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
int err, srate, mclk, min_mclk, sample_size;
+ int i2s_daifmt;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -414,10 +429,32 @@ static int tegra_bt_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(rtd->cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[BT_SCO].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
+ err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt);
if (err < 0) {
dev_err(rtd->codec->card->dev, "cpu_dai fmt not set\n");
return err;
@@ -598,8 +635,9 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_max98088 *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk;
- int err;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, i2s_daifmt;
+ int err, rate;
srate = params_rate(params);
switch (srate) {
@@ -623,6 +661,31 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream,
break;
}
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
if (!(machine->util_data.set_mclk % mclk))
@@ -635,17 +698,15 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "codec_dai fmt not set\n");
return err;
}
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
@@ -655,14 +716,6 @@ static int tegra_voice_call_hw_params(struct snd_pcm_substream *substream,
/* codec configuration */
machine->codec_info[HIFI_CODEC].rate = params_rate(params);
machine->codec_info[HIFI_CODEC].channels = params_channels(params);
- machine->codec_info[HIFI_CODEC].bitsize = 16;
- machine->codec_info[HIFI_CODEC].is_i2smaster = 1;
- machine->codec_info[HIFI_CODEC].is_format_dsp = 0;
-
- /* baseband configuration */
- machine->codec_info[BASEBAND].bitsize = 16;
- machine->codec_info[BASEBAND].is_i2smaster = 1;
- machine->codec_info[BASEBAND].is_format_dsp = 1;
#endif
machine->is_device_bt = 0;
@@ -729,14 +782,6 @@ static int tegra_bt_voice_call_hw_params(struct snd_pcm_substream *substream,
/* codec configuration */
machine->codec_info[BT_SCO].rate = params_rate(params);
machine->codec_info[BT_SCO].channels = params_channels(params);
- machine->codec_info[BT_SCO].bitsize = 16;
- machine->codec_info[BT_SCO].is_i2smaster = 1;
- machine->codec_info[BT_SCO].is_format_dsp = 1;
-
- /* baseband configuration */
- machine->codec_info[BASEBAND].bitsize = 16;
- machine->codec_info[BASEBAND].is_i2smaster = 1;
- machine->codec_info[BASEBAND].is_format_dsp = 1;
#endif
machine->is_device_bt = 1;
@@ -1148,16 +1193,22 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev)
#endif
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
- for (i = 0; i < NUM_I2S_DEVICES ; i++)
- machine->codec_info[i].i2s_id = pdata->audio_port_id[i];
-
- machine->codec_info[BASEBAND].rate = pdata->baseband_param.rate;
- machine->codec_info[BASEBAND].channels = pdata->baseband_param.channels;
- machine->codec_info[BASEBAND].is_format_dsp = 0;
-
- if ((pdata->baseband_param.bit_format == TEGRA_DAIFMT_DSP_A) ||
- (pdata->baseband_param.bit_format == TEGRA_DAIFMT_DSP_B)) {
- machine->codec_info[BASEBAND].is_format_dsp = 1;
+ for (i = 0; i < NUM_I2S_DEVICES ; i++) {
+ machine->codec_info[i].i2s_id =
+ pdata->i2s_param[i].audio_port_id;
+ machine->codec_info[i].bitsize =
+ pdata->i2s_param[i].sample_size;
+ machine->codec_info[i].is_i2smaster =
+ pdata->i2s_param[i].is_i2s_master;
+ machine->codec_info[i].rate =
+ pdata->i2s_param[i].rate;
+ machine->codec_info[i].channels =
+ pdata->i2s_param[i].channels;
+ if ((pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_A) ||
+ (pdata->i2s_param[i].i2s_mode == TEGRA_DAIFMT_DSP_B))
+ machine->codec_info[i].is_format_dsp = 1;
+ else
+ machine->codec_info[i].is_format_dsp = 0;
}
tegra_max98088_dai[DAI_LINK_HIFI].cpu_dai_name =
@@ -1180,6 +1231,16 @@ static __devinit int tegra_max98088_driver_probe(struct platform_device *pdev)
goto err_unregister_card;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+#endif
+
return 0;
err_unregister_card:
diff --git a/sound/soc/tegra/tegra_max98095.c b/sound/soc/tegra/tegra_max98095.c
index d065b78164ac..1d03980f276f 100644
--- a/sound/soc/tegra/tegra_max98095.c
+++ b/sound/soc/tegra/tegra_max98095.c
@@ -8,7 +8,7 @@
*
* Based on code copyright/by:
*
- * (c) 2010, 2011, 2012 Nvidia Graphics Pvt. Ltd.
+ * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved.
*
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
@@ -32,6 +32,7 @@
#include <asm/mach-types.h>
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -118,11 +119,12 @@ static int tegra_max98095_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_max98095 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
#ifndef CONFIG_ARCH_TEGRA_2x_SOC
struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(cpu_dai);
#endif
- unsigned int srate, mclk, sample_size;
- int err;
+ unsigned int srate, mclk, sample_size, i2s_daifmt;
+ int err, rate;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
@@ -154,6 +156,31 @@ static int tegra_max98095_hw_params(struct snd_pcm_substream *substream,
break;
}
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
if (!(machine->util_data.set_mclk % mclk))
@@ -166,26 +193,20 @@ static int tegra_max98095_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(codec_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+ err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "codec_dai fmt not set\n");
return err;
}
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt);
if (err < 0) {
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);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
@@ -667,6 +688,16 @@ static __devinit int tegra_max98095_driver_probe(struct platform_device *pdev)
goto err_unregister_card;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_switch_unregister;
+ }
+#endif
+
return 0;
err_unregister_card:
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 090e8481dc37..8bd0af7df610 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -74,7 +74,10 @@ static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd)
dma_req = &prtd->dma_req[prtd->dma_req_idx];
- addr = buf->addr + prtd->dma_pos;
+ if (prtd->avp_dma_addr)
+ addr = prtd->avp_dma_addr + prtd->dma_pos;
+ else
+ addr = buf->addr + prtd->dma_pos;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_req->source_addr = addr;
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index b63de32023e8..5a9531b9fbf7 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -54,6 +54,7 @@ struct tegra_runtime_data {
struct tegra_dma_channel *dma_chan;
int dma_req_count;
int disable_intr;
+ unsigned int avp_dma_addr;
};
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 765eb59fabae..a99711fb9234 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -10,6 +10,7 @@
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
+ * 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 published by the Free Software Foundation.
@@ -28,6 +29,7 @@
#include <asm/mach-types.h>
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -37,7 +39,7 @@
#include <linux/switch.h>
#endif
-#include <mach/tegra_rt5640_pdata.h>
+#include <mach/tegra_asoc_pdata.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -61,7 +63,7 @@
struct tegra_rt5640 {
struct tegra_asoc_utils_data util_data;
- struct tegra_rt5640_platform_data *pdata;
+ struct tegra_asoc_platform_data *pdata;
struct regulator *spk_reg;
struct regulator *dmic_reg;
struct regulator *cdc_en;
@@ -82,11 +84,38 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
int srate, mclk, i2s_daifmt;
- int err;
+ int err, rate;
srate = params_rate(params);
mclk = 256 * srate;
+
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
if (!(machine->util_data.set_mclk % mclk)) {
@@ -99,10 +128,7 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
-
- i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
@@ -116,8 +142,7 @@ static int tegra_rt5640_hw_params(struct snd_pcm_substream *substream,
return err;
}
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
@@ -130,10 +155,10 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_card *card = rtd->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk, min_mclk;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, min_mclk, i2s_daifmt;
int err;
srate = params_rate(params);
@@ -169,10 +194,32 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[BT_SCO].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
+ err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "cpu_dai fmt not set\n");
return err;
@@ -279,7 +326,7 @@ static int tegra_rt5640_jack_notifier(struct notifier_block *self,
struct snd_soc_codec *codec = jack->codec;
struct snd_soc_card *card = codec->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
enum headset_state state = BIT_NO_HEADSET;
unsigned char status_jack = 0;
@@ -357,7 +404,7 @@ static int tegra_rt5640_event_int_spk(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (machine->spk_reg) {
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -381,7 +428,7 @@ static int tegra_rt5640_event_hp(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (!(machine->gpio_requested & GPIO_HP_MUTE))
return 0;
@@ -398,7 +445,7 @@ static int tegra_rt5640_event_int_mic(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (machine->dmic_reg) {
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -422,7 +469,7 @@ static int tegra_rt5640_event_ext_mic(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (!(machine->gpio_requested & GPIO_EXT_MIC_EN))
return 0;
@@ -467,7 +514,7 @@ static int tegra_rt5640_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = codec->card;
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
int ret;
if (gpio_is_valid(pdata->gpio_spkr_en)) {
@@ -650,7 +697,7 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &snd_soc_tegra_rt5640;
struct tegra_rt5640 *machine;
- struct tegra_rt5640_platform_data *pdata;
+ struct tegra_asoc_platform_data *pdata;
int ret;
pdata = pdev->dev.platform_data;
@@ -716,6 +763,16 @@ static __devinit int tegra_rt5640_driver_probe(struct platform_device *pdev)
goto err_unregister_card;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+#endif
+
return 0;
err_unregister_card:
@@ -735,7 +792,7 @@ static int __devexit tegra_rt5640_driver_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct tegra_rt5640 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_rt5640_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (machine->gpio_requested & GPIO_HP_DET)
snd_soc_jack_free_gpios(&tegra_rt5640_hp_jack,
diff --git a/sound/soc/tegra/tegra_p1852.c b/sound/soc/tegra/tegra_vcm.c
index 199bb8046636..afb444e3f19f 100644
--- a/sound/soc/tegra/tegra_p1852.c
+++ b/sound/soc/tegra/tegra_vcm.c
@@ -1,8 +1,8 @@
/*
- * tegra_p1852.c - Tegra machine ASoC driver for P1852 Boards.
+ * tegra_vcm.c - Tegra machine ASoC driver for P852/P1852/P1853 Boards.
*
* Author: Nitin Pai <npai@nvidia.com>
- * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2010-2012 - NVIDIA, Corporation. All rights reserved.
*
* Based on code copyright/by:
* Copyright (c) 2009-2010, NVIDIA Corporation.
@@ -41,14 +41,23 @@
#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
+#ifdef CONFIG_MACH_P1852
#define DRV_NAME "tegra-snd-p1852"
+#endif
+#ifdef CONFIG_MACH_E1853
+#define DRV_NAME "tegra-snd-e1853"
+#endif
+#ifdef CONFIG_MACH_P852
+#define DRV_NAME "tegra-snd-p852"
+#endif
-struct tegra_p1852 {
+
+struct tegra_vcm {
struct tegra_asoc_utils_data util_data;
struct tegra_p1852_platform_data *pdata;
};
-static int tegra_p1852_hw_params(struct snd_pcm_substream *substream,
+static int tegra_vcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
int codec_id)
{
@@ -57,7 +66,7 @@ static int tegra_p1852_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
- struct tegra_p1852 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_vcm *machine = snd_soc_card_get_drvdata(card);
int srate, mclk;
int i2s_daifmt = 0;
int err;
@@ -139,64 +148,64 @@ static int tegra_p1852_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int tegra_p1852_hw_params_controller1(
+static int tegra_vcm_hw_params_controller1(
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- return tegra_p1852_hw_params(substream, params, 0);
+ return tegra_vcm_hw_params(substream, params, 0);
}
-static int tegra_p1852_hw_params_controller2(
+static int tegra_vcm_hw_params_controller2(
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- return tegra_p1852_hw_params(substream, params, 1);
+ return tegra_vcm_hw_params(substream, params, 1);
}
static int tegra_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct tegra_p1852 *machine = snd_soc_card_get_drvdata(rtd->card);
+ struct tegra_vcm *machine = snd_soc_card_get_drvdata(rtd->card);
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 0);
return 0;
}
-static struct snd_soc_ops tegra_p1852_ops_controller1 = {
- .hw_params = tegra_p1852_hw_params_controller1,
+static struct snd_soc_ops tegra_vcm_ops_controller1 = {
+ .hw_params = tegra_vcm_hw_params_controller1,
.hw_free = tegra_hw_free,
};
-static struct snd_soc_ops tegra_p1852_ops_controller2 = {
- .hw_params = tegra_p1852_hw_params_controller2,
+static struct snd_soc_ops tegra_vcm_ops_controller2 = {
+ .hw_params = tegra_vcm_hw_params_controller2,
.hw_free = tegra_hw_free,
};
-static struct snd_soc_dai_link tegra_p1852_dai_link[] = {
+static struct snd_soc_dai_link tegra_vcm_dai_link[] = {
{
.name = "I2S-TDM-1",
.stream_name = "TEGRA PCM",
.platform_name = "tegra-pcm-audio",
- .ops = &tegra_p1852_ops_controller1,
+ .ops = &tegra_vcm_ops_controller1,
},
{
.name = "I2S-TDM-2",
.stream_name = "TEGRA PCM",
.platform_name = "tegra-pcm-audio",
- .ops = &tegra_p1852_ops_controller2,
+ .ops = &tegra_vcm_ops_controller2,
}
};
-static struct snd_soc_card snd_soc_tegra_p1852 = {
- .name = "tegra-p1852",
- .dai_link = tegra_p1852_dai_link,
- .num_links = ARRAY_SIZE(tegra_p1852_dai_link),
+static struct snd_soc_card snd_soc_tegra_vcm = {
+ .name = "tegra-vcm",
+ .dai_link = tegra_vcm_dai_link,
+ .num_links = ARRAY_SIZE(tegra_vcm_dai_link),
};
-static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev)
+static __devinit int tegra_vcm_driver_probe(struct platform_device *pdev)
{
- struct snd_soc_card *card = &snd_soc_tegra_p1852;
- struct tegra_p1852 *machine;
+ struct snd_soc_card *card = &snd_soc_tegra_vcm;
+ struct tegra_vcm *machine;
struct tegra_p1852_platform_data *pdata;
int ret;
int i;
@@ -207,9 +216,9 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev)
return -EINVAL;
}
- machine = kzalloc(sizeof(struct tegra_p1852), GFP_KERNEL);
+ machine = kzalloc(sizeof(struct tegra_vcm), GFP_KERNEL);
if (!machine) {
- dev_err(&pdev->dev, "Can't allocate tegra_p1852 struct\n");
+ dev_err(&pdev->dev, "Can't allocate tegra_vcm struct\n");
return -ENOMEM;
}
@@ -218,17 +227,17 @@ static __devinit int tegra_p1852_driver_probe(struct platform_device *pdev)
/* The codec driver and codec dai have to come from the system
* level board configuration file
* */
- for (i = 0; i < ARRAY_SIZE(tegra_p1852_dai_link); i++) {
- tegra_p1852_dai_link[i].codec_name =
+ for (i = 0; i < ARRAY_SIZE(tegra_vcm_dai_link); i++) {
+ tegra_vcm_dai_link[i].codec_name =
pdata->codec_info[i].codec_name;
- tegra_p1852_dai_link[i].cpu_dai_name =
+ tegra_vcm_dai_link[i].cpu_dai_name =
pdata->codec_info[i].cpu_dai_name;
- tegra_p1852_dai_link[i].codec_dai_name =
+ tegra_vcm_dai_link[i].codec_dai_name =
pdata->codec_info[i].codec_dai_name;
- tegra_p1852_dai_link[i].name =
+ tegra_vcm_dai_link[i].name =
pdata->codec_info[i].name;
if (pdata->codec_info[i].pcm_driver)
- tegra_p1852_dai_link[i].platform_name =
+ tegra_vcm_dai_link[i].platform_name =
pdata->codec_info[i].pcm_driver;
}
@@ -263,10 +272,10 @@ err_free_machine:
return ret;
}
-static int __devexit tegra_p1852_driver_remove(struct platform_device *pdev)
+static int __devexit tegra_vcm_driver_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- struct tegra_p1852 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_vcm *machine = snd_soc_card_get_drvdata(card);
snd_soc_unregister_card(card);
tegra_asoc_utils_fini(&machine->util_data);
@@ -275,29 +284,29 @@ static int __devexit tegra_p1852_driver_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver tegra_p1852_driver = {
+static struct platform_driver tegra_vcm_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = &snd_soc_pm_ops,
},
- .probe = tegra_p1852_driver_probe,
- .remove = __devexit_p(tegra_p1852_driver_remove),
+ .probe = tegra_vcm_driver_probe,
+ .remove = __devexit_p(tegra_vcm_driver_remove),
};
-static int __init tegra_p1852_modinit(void)
+static int __init tegra_vcm_modinit(void)
{
- return platform_driver_register(&tegra_p1852_driver);
+ return platform_driver_register(&tegra_vcm_driver);
}
-module_init(tegra_p1852_modinit);
+module_init(tegra_vcm_modinit);
-static void __exit tegra_p1852_modexit(void)
+static void __exit tegra_vcm_modexit(void)
{
- platform_driver_unregister(&tegra_p1852_driver);
+ platform_driver_unregister(&tegra_vcm_driver);
}
-module_exit(tegra_p1852_modexit);
+module_exit(tegra_vcm_modexit);
MODULE_AUTHOR("Nitin Pai <npai@nvidia.com>");
-MODULE_DESCRIPTION("Tegra+P1852 machine ASoC driver");
+MODULE_DESCRIPTION("Tegra+VCM machine ASoC driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
index f7c7a4c6b5a1..f1b9335ab473 100644
--- a/sound/soc/tegra/tegra_wm8753.c
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -12,6 +12,7 @@
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
+ * 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 published by the Free Software Foundation.
@@ -30,6 +31,7 @@
#include <asm/mach-types.h>
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -83,8 +85,10 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
int srate, mclk, i2s_daifmt;
- int err;
+ int err, rate;
+
srate = params_rate(params);
switch (srate) {
case 8000:
@@ -119,14 +123,38 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[HIFI_CODEC].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
/* Use DSP mode for mono on Tegra20 */
- if ((params_channels(params) != 2) && machine_is_whistler())
+ if ((params_channels(params) != 2) && machine_is_whistler()) {
i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
- else
- i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ } else {
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev,
+ "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+ }
err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
@@ -140,8 +168,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
return err;
}
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
@@ -173,7 +200,8 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk, min_mclk;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, min_mclk, i2s_daifmt;
int err;
srate = params_rate(params);
@@ -209,10 +237,32 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[BT_SCO].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
+ err = snd_soc_dai_set_fmt(cpu_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "cpu_dai fmt not set\n");
return err;
@@ -873,8 +923,6 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
return -ENOMEM;
}
- machine->pdata = pdata;
-
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev, card);
if (ret)
goto err_free_machine;
@@ -904,6 +952,16 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
}
#endif
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+#endif
+
return 0;
err_unregister_card:
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 063aefe50507..dcd031209172 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -12,6 +12,8 @@
* Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
*
+ * 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 published by the Free Software Foundation.
@@ -40,7 +42,7 @@
#include <linux/switch.h>
#endif
-#include <mach/tegra_wm8903_pdata.h>
+#include <mach/tegra_asoc_pdata.h>
#include <sound/core.h>
#include <sound/jack.h>
@@ -67,7 +69,7 @@
struct tegra_wm8903 {
struct tegra_asoc_utils_data util_data;
- struct tegra_wm8903_platform_data *pdata;
+ struct tegra_asoc_platform_data *pdata;
struct regulator *spk_reg;
struct regulator *dmic_reg;
int gpio_requested;
@@ -86,9 +88,9 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *card = codec->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
int srate, mclk, i2s_daifmt;
int err;
- struct clk *clk_m;
int rate;
srate = params_rate(params);
@@ -103,31 +105,17 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
break;
}
+ if(pdata->i2s_param[HIFI_CODEC].is_i2s_master) {
+ /* FIXME: Codec only requires >= 3MHz if OSR==0 */
+ while (mclk < 6000000)
+ mclk *= 2;
-
- clk_m = clk_get_sys(NULL, "clk_m");
- if (IS_ERR(clk_m)) {
- dev_err(card->dev, "Can't retrieve clk clk_m\n");
- err = PTR_ERR(clk_m);
- return err;
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS;
+ } else {
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
}
- rate = clk_get_rate(clk_m);
- printk("extern1 rate=%d\n",rate);
-
-#if TEGRA30_I2S_MASTER_PLAYBACK
- /* FIXME: Codec only requires >= 3MHz if OSR==0 */
- while (mclk < 6000000)
- mclk *= 2;
-
- i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
-#else
- mclk = rate;
-
- i2s_daifmt = SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBM_CFM;
-#endif
-
err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
if (err < 0) {
@@ -141,13 +129,36 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
+ rate = clk_get_rate(machine->util_data.clk_cdev1);
+
/* Use DSP mode for mono on Tegra20 */
if ((params_channels(params) != 2) &&
- (machine_is_ventana() || machine_is_harmony() ||
- machine_is_kaen() || machine_is_aebl()))
+ (machine_is_ventana() || machine_is_harmony() ||
+ machine_is_kaen() || machine_is_aebl())) {
i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
- else
- i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ } else {
+ switch (pdata->i2s_param[HIFI_CODEC].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev,
+ "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+ }
err = snd_soc_dai_set_fmt(codec_dai, i2s_daifmt);
if (err < 0) {
@@ -161,8 +172,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream,
return err;
}
- err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
- SND_SOC_CLOCK_IN);
+ err = snd_soc_dai_set_sysclk(codec_dai, 0, rate, SND_SOC_CLOCK_IN);
if (err < 0) {
dev_err(card->dev, "codec_dai clock not set\n");
return err;
@@ -190,10 +200,10 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_card *card = rtd->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- int srate, mclk, min_mclk;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
+ int srate, mclk, min_mclk, i2s_daifmt;
int err;
srate = params_rate(params);
@@ -229,10 +239,32 @@ static int tegra_bt_sco_hw_params(struct snd_pcm_substream *substream,
tegra_asoc_utils_lock_clk_rate(&machine->util_data, 1);
- err = snd_soc_dai_set_fmt(cpu_dai,
- SND_SOC_DAIFMT_DSP_A |
- SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS);
+ i2s_daifmt = SND_SOC_DAIFMT_NB_NF;
+ i2s_daifmt |= pdata->i2s_param[BT_SCO].is_i2s_master ?
+ SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBM_CFM;
+
+ switch (pdata->i2s_param[BT_SCO].i2s_mode) {
+ case TEGRA_DAIFMT_I2S :
+ i2s_daifmt |= SND_SOC_DAIFMT_I2S;
+ break;
+ case TEGRA_DAIFMT_DSP_A :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_A;
+ break;
+ case TEGRA_DAIFMT_DSP_B :
+ i2s_daifmt |= SND_SOC_DAIFMT_DSP_B;
+ break;
+ case TEGRA_DAIFMT_LEFT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_LEFT_J;
+ break;
+ case TEGRA_DAIFMT_RIGHT_J :
+ i2s_daifmt |= SND_SOC_DAIFMT_RIGHT_J;
+ break;
+ default :
+ dev_err(card->dev, "Can't configure i2s format\n");
+ return -EINVAL;
+ }
+
+ err = snd_soc_dai_set_fmt(rtd->cpu_dai, i2s_daifmt);
if (err < 0) {
dev_err(card->dev, "cpu_dai fmt not set\n");
return err;
@@ -408,7 +440,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (machine->spk_reg) {
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -432,7 +464,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (!(machine->gpio_requested & GPIO_HP_MUTE))
return 0;
@@ -449,7 +481,7 @@ static int tegra_wm8903_event_int_mic(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (machine->dmic_reg) {
if (SND_SOC_DAPM_EVENT_ON(event))
@@ -473,7 +505,7 @@ static int tegra_wm8903_event_ext_mic(struct snd_soc_dapm_widget *w,
struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_card *card = dapm->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (!(machine->gpio_requested & GPIO_EXT_MIC_EN))
return 0;
@@ -578,7 +610,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_card *card = codec->card;
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
int ret;
machine->bias_level = SND_SOC_BIAS_STANDBY;
@@ -792,7 +824,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &snd_soc_tegra_wm8903;
struct tegra_wm8903 *machine;
- struct tegra_wm8903_platform_data *pdata;
+ struct tegra_asoc_platform_data *pdata;
int ret;
pdata = pdev->dev.platform_data;
@@ -895,6 +927,16 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
goto err_unregister_card;
}
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ ret = tegra_asoc_utils_set_parent(&machine->util_data,
+ pdata->i2s_param[HIFI_CODEC].is_i2s_master);
+ if (ret) {
+ dev_err(&pdev->dev, "tegra_asoc_utils_set_parent failed (%d)\n",
+ ret);
+ goto err_unregister_card;
+ }
+#endif
+
return 0;
err_unregister_card:
@@ -914,7 +956,7 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
- struct tegra_wm8903_platform_data *pdata = machine->pdata;
+ struct tegra_asoc_platform_data *pdata = machine->pdata;
if (machine->gpio_requested & GPIO_HP_DET)
snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack,
diff --git a/sound/usb/card.c b/sound/usb/card.c
index d8f2bf401458..d5201ca996e4 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -35,7 +35,6 @@
* indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream).
*/
-
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -47,6 +46,9 @@
#include <linux/mutex.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
+#ifdef CONFIG_SWITCH
+#include <linux/switch.h>
+#endif
#include <sound/control.h>
#include <sound/core.h>
@@ -115,6 +117,18 @@ static DEFINE_MUTEX(register_mutex);
static struct snd_usb_audio *usb_chip[SNDRV_CARDS];
static struct usb_driver usb_audio_driver;
+#ifdef CONFIG_SWITCH
+enum switch_state {
+ STATE_CONNECTED_UNKNOWN = -1,
+ STATE_DISCONNECTED = 0,
+ STATE_CONNECTED = 1
+};
+
+static struct switch_dev usb_switch_dev = {
+ .name = "usb_audio",
+};
+#endif
+
/*
* disconnect streams
* called from snd_usb_audio_disconnect()
@@ -523,10 +537,15 @@ snd_usb_audio_probe(struct usb_device *dev,
goto __error;
}
+#ifdef CONFIG_SWITCH
+ switch_set_state(&usb_switch_dev, STATE_CONNECTED);
+#endif
+
usb_chip[chip->index] = chip;
chip->num_interfaces++;
chip->probing = 0;
mutex_unlock(&register_mutex);
+
return chip;
__error:
@@ -537,6 +556,7 @@ snd_usb_audio_probe(struct usb_device *dev,
}
mutex_unlock(&register_mutex);
__err_val:
+
return NULL;
}
@@ -558,6 +578,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
mutex_lock(&chip->shutdown_mutex);
chip->shutdown = 1;
chip->num_interfaces--;
+
+#ifdef CONFIG_SWITCH
+ switch_set_state(&usb_switch_dev, STATE_DISCONNECTED);
+#endif
+
if (chip->num_interfaces <= 0) {
snd_card_disconnect(card);
/* release the pcm resources */
@@ -712,15 +737,37 @@ static struct usb_driver usb_audio_driver = {
static int __init snd_usb_audio_init(void)
{
+ int err = 0;
+
if (nrpacks < 1 || nrpacks > MAX_PACKS) {
printk(KERN_WARNING "invalid nrpacks value.\n");
return -EINVAL;
}
- return usb_register(&usb_audio_driver);
+
+#ifdef CONFIG_SWITCH
+ /* Add usb_audio swith class support */
+ err = switch_dev_register(&usb_switch_dev);
+ if (err < 0){
+ printk(KERN_ERR "failed to register switch device");
+ return -EINVAL;
+ }
+#endif
+
+ err = usb_register(&usb_audio_driver);
+ if (err) {
+#ifdef CONFIG_SWITCH
+ switch_dev_unregister(&usb_switch_dev);
+#endif
+ }
+
+ return err;
}
static void __exit snd_usb_audio_cleanup(void)
{
+#ifdef CONFIG_SWITCH
+ switch_dev_unregister(&usb_switch_dev);
+#endif
usb_deregister(&usb_audio_driver);
}